6
votes
#include <stdio.h>

int main() {
    printf("sizeof(int): %zu\n", sizeof(int));
    printf("%d\n", 2147483648u > -2147483648);
    printf("%d\n", ((unsigned int)2147483648u) > ((int)-2147483648));
    printf("%d\n", 2147483648u != -2147483648);
    printf("%d\n", ((unsigned int)2147483648u) != ((int)-2147483648));
    return 0;
}

The output of this code in both C and C++, on cygwin64 and an rhel6.4 machine with gcc 5.2.0 is:

sizeof(int): 4
1
0
1
0

According to "Integer promotions", 2147483648u will be of type unsigned int (even without the u suffix) and -2147483648 of type int (as usual). Why the different results with explicit casting?

According to the "Usual arithmetic conversions", this paragraph applies:

Otherwise, the signedness is different: If the operand with the unsigned type has conversion rank greater or equal than the rank of the type of the signed operand, then the operand with the signed type is implicitly converted to the unsigned type

This means that the correct result is as if:

2147483648u > 2147483648u
2147483648u != 2147483648u

were performed, because in 32 bits, signed -2^31 and unsigned 2^31 have the same representation. In other words, the result with casting is correct. What is going on?

I have the feeling that somehow, a higher-rank integer promotion is applied without casting, so I'm getting e.g. a 64-bit signed promotion on both sides -- but why?

Both executables are compiled as 64-bit, can this play a role?

1
@FUZxxl: Isn't, in this case. - DevSolar
@FUZxxl: I think this "they are different" on SO is going a bit too far in some places. This one, for example. - DevSolar
@FUZxxl: I have made multiply sure that the behavior is identical in both languages (and between individual standards that are in common usage today). It belongs in both categories. - Irfy
@Irfy No, it doesn't. Please pick one. If I said “I made sure 1+1 does the same thing in languages x, y, and z so my question about 1+1 belongs to all of them” that would be just as wrong. - fuz
@FUZxxl: It's OK if you don't want to have the discussion, but please draw the line at telling people that something was "decided" on meta when it wasn't, at least not the last time I looked. - DevSolar

1 Answers

13
votes

There are no negative integer constants. There are only positive ones with the unary - operator applied.

Since 2147483648 > INT_MAX, that promotes 2147483648 to the next larger signed (because you did not append u) integer type, before the - is applied.


By the way, that is why INT_MIN is usually defined as (-INT_MAX - 1) in <limits.h>. ;-)