0

This is the code:

unsigned int c;
signed int d = -1;
c = d;
if(c == d) 
    printf("c == d\n");

Running this gives the output: c == d.

The variable c can not be negative right?

Lokkij
  • 424
  • 4
  • 15
Radoslaw Krasimirow
  • 1,833
  • 2
  • 18
  • 28
  • 2
    Yes. But everything has a binary repression. Compile with warnings – Ed Heal Aug 27 '15 at 18:07
  • 4
    possible duplicate of [Compare int and unsigned int](http://stackoverflow.com/questions/8233161/compare-int-and-unsigned-int) – cegfault Aug 27 '15 at 18:08
  • It is't strange at all. Implicit conversion is at work. http://stackoverflow.com/questions/2084949/arithmetic-operations-on-unsigned-and-signed-integers/2085031#2085031 – alvits Aug 27 '15 at 18:09
  • 1
    Note: It's not a compiler output. Fix the title. – Eugene Sh. Aug 27 '15 at 18:11

6 Answers6

7

According to the rules of usual arithmetic conversions, expression c == d is interpreted as c == (unsigned int) d. More specifically, when you mix signed int and unsigned int operands in equality comparison operator, the signed int operand is implicitly converted to unsigned int type before the comparison. The same is true for majority of binary operators in C.

At the same time, you assigned the value of c as c = d, which is equivalent to c = (unsigned int) d.

So, as you can immediately see, you are comparing the same thing to the same thing: you are essentially comparing (unsigned int) d to (unsigned int) d. No wonder the equality holds.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
4

When if(c==d) is executed, it does an implicit type conversion before checking. After the type conversion, they are equal, so the expression is true.

In answer to the question, "The variable c can not be negative right?" you are correct that c cannot be negative.

Almo
  • 15,538
  • 13
  • 67
  • 95
  • 3
    The answer is terse, but adequate. The phrase _implicit type conversion_ is sufficient to explain all that is necessary to explain. – ryyker Aug 27 '15 at 18:19
  • Answer is correct and adequate. But does not reply the question : The variable c can not be negative right? – Anonymous Coward Aug 27 '15 at 18:41
1

According to the standard - the signed int, will be converted to unsigned int.

Check "6.3.1.8 Usual arithmetic conversions" on Page 53 in

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

If the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

When d is assigned -1, d holds 0xFFFFFFFF (Two's Complement)

and when c is assigned d, c holds 0xFFFFFFFF

then you compare c and d as in if (c == d), the two variables are compared as dword - and they are the same value - hence it prints "c==d"

abRao
  • 2,787
  • 1
  • 25
  • 37
1

Indeed, c cannot be negative. So c and d are holding different values. Yet still the comparision c==d is correctly evaluated as true.

The reason is that they are of different types. And different types can't be directly compared. When the compiler enconters such an expresion with different types it must follow cetain rules detailed in the standard to convert those values to a common type. And that conversion may change the value which is being evaluated.

In this particular case those rules say that d is implicitly converted to unsigned before evaluation of == and c is evaluated as is.

  • In the left side we have c, which already is holding the result of converting -1 to unsigned (because c is unsigned and was assigned d, which held -1). c is evaluated as is so left side is evaluated as -1 converted to unsigned.
  • In the right side we have d, which holds -1. Right side is evaluated with conversion to unsigned, so right side evaluates as -1 converted to unsigned.

So both sides of == end up being evaluated as -1 converted to unsigned. Both sides are equal so expresion evaluates to true (1).

Note : Some might be suprised about the claim that c and d hold different values. But this is true even if their binary representation is exactly the same. The bits may be the same but the values they represent are different. Also note that those values, which are different, are not compared. Rather one of those values is compared to a conversion of the other one.
That all of this ends up being just a single CMP assembly instruction which is not really converting anything at all since that conversion is already implicit in the way those values are stored in the computer is just an implementation detail.

Anonymous Coward
  • 3,140
  • 22
  • 39
0

Both signed and unsigend ints are really just a bunch of bits and bytes. So actually -1 is the max value of a signed int. Therefore when you assign them they will be equal. Try printing out c and d.

Take a look at this to understand how signed integers work. http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html

chasep255
  • 11,745
  • 8
  • 58
  • 115
  • While this might be true at the low-level on a given platform, it has nothig to do with C language itself. C langauge does not generally treat signed and unsigned types as "just a bunch of bits and bytes". – AnT stands with Russia Aug 27 '15 at 18:25
0

The conversion rules for ANSI C state:

[In case of mixing signed and unsigned values]

[...] if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
[...]

The new type is unsigned int. The maximum value is likely 232. One more than the maximum value is 232 + 1. Adding one more than the maximum value to the value is -1 + 232+1, which is again 232.

So c, which cannot contain -1, will contain instead 232.

Now, if you compare c and d, the very same conversion (!) is applied internally to compare d with c, as ANSI C only compares values with the same datatype, so first the same datatype for both variables is created. And as the very same conversion to the very same number is performed to create two comparable numbers, the result is true.

John Hammond
  • 467
  • 1
  • 4
  • 14