6
#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?

Irfy
  • 9,323
  • 1
  • 45
  • 67
  • Please choose one of C and C++. These two languages are different and the answer might be different for both of them. – fuz Feb 01 '16 at 12:54
  • 2
    @FUZxxl: Isn't, in this case. – DevSolar Feb 01 '16 at 12:55
  • Also, which C standard are you compiling against? Handling of integer constants changed in C11. – fuz Feb 01 '16 at 12:55
  • @DevSolar Still, not a reason to accept a C/C++ question. Ask two questions if you want to have an explanation looked up in both standards. – fuz Feb 01 '16 at 12:56
  • 3
    @FUZxxl: I think this "they are different" on SO is going a bit too far in some places. This one, for example. – DevSolar Feb 01 '16 at 12:56
  • @DevSolar I'm not having this conservation again. It was decided on meta that you may not ask C/C++ questions except if the question is specifically about the difference or about the interaction between these two. End of discussions. – fuz Feb 01 '16 at 12:58
  • 1
    @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 Feb 01 '16 at 12:58
  • 1
    @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 Feb 01 '16 at 12:58
  • @Irfy Also: Even if the behaviour is equal, the reason why the behaviour is this way may not be and you cannot demand people to lookup answers in both standards. – fuz Feb 01 '16 at 12:59
  • And lastly, you haven't answered my question: What C standard are you compiling against? Because handing of integer constants changed in C11 and the answer will be different. – fuz Feb 01 '16 at 13:00
  • @FUZxxl: This discussion is really unnecessary. Also, the behavior is identical between `-std={c,gnu}++{98,03,11,14}` and `-std={c,gnu}{89/99/11}` with GCC 5.2.0 -- which I already implied in my previous comment. I'm out. – Irfy Feb 01 '16 at 13:09
  • 3
    @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](http://meta.stackoverflow.com/questions/252430). – DevSolar Feb 01 '16 at 13:20

1 Answers1

13

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>. ;-)

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 1
    Wow, this never hit me in about 17 years of coding in c/c++ :-) – Irfy Feb 01 '16 at 13:01
  • In *my* case, I'm lucky and that is the case. However win64's long is 4 bytes, so if i had that done with a VC compiler, it wouldn't have been the case. – Irfy Feb 01 '16 at 14:10
  • If you're trying to hit a limit, try entering -2^63 and -2^127 (computed) as a literal :) – Irfy Feb 01 '16 at 14:15
  • 2
    @lrfy: With `(-LLONG_MAX - 1)`, the former is (comparatively) easy. The latter, to my knowledge, doesn't work without using multiplication of smaller-width constants or bit shifting. GCC supports `__int128_t`, but not the integer constant widths to go with it. – DevSolar Feb 01 '16 at 14:17