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?
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?
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.
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.
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
"
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.
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. 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.
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
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.