Reputation: 802
Please have a look at the following code snippet, which basically simply bit shifts 1 byte by 24 bits to the left.
uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFF << 24;
printf("after : %016llX \n", i);
// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFEFF000000
The most significant 32 bits are FFFFFFFE
(watch the E
at the end). This is not as I expected. I don't see why shifting 1 bytes 24 bits left would touch bit #32 (bit #31 should be the last one modified) It changed the last F
(1111
) into E
(1110
)).
To make it work properly, I had use 0xFF
unsigned (0xFFU
).
uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFFU << 24;
printf("after : %016llX \n", i);
// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFFFF000000
Why does the bit shift with a signed int (0xFF
) touch/reset one bit too much?
Upvotes: 5
Views: 239
Reputation: 223689
You left-shifted into the sign bit.
The integer constant 0xFF
has type int
. Assuming an int
is 32 bit, the expression 0xFF << 24
shifts a bit set to 1 into the high-order bit of a signed integer triggers undefined behavior which in your case manifested as an unexpected value.
This is spelled out in section 6.5.7p4 of the C standard:
The result of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are filled with zeros. IfE1
has an unsigned type, the value of the result is E1×2E2, reduced modulo one more than the maximum value representable in the result type. IfE1
has a signed type and nonnegative value, and E1×2E2is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
By using the U
suffix this makes the constant have type unsigned int
, and it is valid to shift bits set to 1 into the high-order bit because there is no sign bit.
Upvotes: 3