geohei
geohei

Reputation: 802

Bit shift with a signed int resets one bit too much

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

Answers (1)

dbush
dbush

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 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 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. If E1 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

Related Questions