I wrote the following c code:
#include <stdio.h>
int main () {
printf("%d\n", -1 >> 8);
return 0;
}
I compile this code with gcc 4.6.3 on my x86_64 using the -m32 flag. I get -1 printed out as I would expect, the shift occurs arithmetically using two's complement representation resulting in -1.
Now if I instead write
printf("%d\n", 0xFFFFFFFF >> 8);
I get 16777215. I would have expected this constant to be interpreted as an int (signed) and then the shift to be arithmetic which would result in -1 again. I've looked through the latest C standard and I can't seem to understand why this is the case. Any ideas?
According to the C99 standard (6.4.4.1), hexadecimal constants will be the first type on this list that can represent them:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
The hex literal 0xFFFFFFFF
does not fit in an int
(which can hold the values -0x80000000
to 0x7FFFFFFF
), but does fit in unsigned int
, and therefore its type will be unsigned. Right-shifting the unsigned value 0xFFFFFFFF
by 8 gives 16777215
.
Undecorated integral literals have different type depending on whether they are decimal or not (6.4.4.1/5 in C11, Table 6 in C++11):
decimal literals, i.e. [1-9][0-9]*
, are always signed.
hexadecimal and octal literals are either signed or unsigned. If the value is to large for a signed type, but small enough to fit the unsigned type of the same width, it will be unsigned. (This is what happens to your hex constant.)
Right-shifting negative integers is implementation-defined, and you happen to get sign-extension. Right-shifting the unsigned value is simple division by two.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With