I recently discovered a discrepancy between two ways to set a variable to all 1s in C. Here is a small code sample to illustrate the odd behaviour on my 64 bit Linux system.
// compile with `gcc -o weird_shift_behaviour weird_shift_behaviour.c`
#include <stdio.h>
int main(void){
long long foo = 0;
long long bar = 0;
int i;
puts("<foo> will be set to all 1s by repeatedly shifting 1 to the left and OR-ing the result with <foo>.");
puts("<bar> will be set to all 1s by repeatedly OR-ing it with 1 and shifting <bar> to the left one step.");
for(i=0;i<8*(int)sizeof(long long)-1;++i){
foo |= (1<<i);
bar = bar<<1 | 1;
printf("<i>: %02d <foo>: %016llx <bar>: %016llx \n",i,foo,bar);
}
return 0;
}
I do know that this is not the canonical way to set an integer type to all 1s in C, but I did try it nonetheless. Here is the interesting part of the output the sample program generates:
<i>: 29 <foo>: 000000003fffffff <bar>: 000000003fffffff
<i>: 30 <foo>: 000000007fffffff <bar>: 000000007fffffff
<i>: 31 <foo>: ffffffffffffffff <bar>: 00000000ffffffff
<i>: 32 <foo>: ffffffffffffffff <bar>: 00000001ffffffff
Why does this odd behaviour occur? I could not think of any reasonable explanation so far.
1<<i
1
is of type int
and 1 << 31
is undefined behavior when int
is 32-bit wide.
From the C Standard:
(C99, 6.5.7p4) "The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 x 2 ^ E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined."
To fix your issue, change 1<<i
with 1ULL << i
.
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