What are the 5bits and the 6bits in when bit shifting by the size of the integer?

66 Views Asked by At

I'm referring to this article specifically this part

Oversized Shift Amounts: Shifting a uint32_t by 32 or more bits is undefined. My guess is that this originated because the underlying shift operations on various CPUs do different things with this: for example, X86 truncates 32-bit shift amount to 5 bits (so a shift by 32-bits is the same as a shift by 0-bits), but PowerPC truncates 32-bit shift amounts to 6 bits (so a shift by 32 produces zero). Because of these hardware differences, the behavior is completely undefined by C (thus shifting by 32-bits on PowerPC could format your hard drive, it is not guaranteed to produce zero). The cost of eliminating this undefined behavior is that the compiler would have to emit an extra operation (like an 'and') for variable shifts, which would make them twice as expensive on common CPUs.

What are those 5 bits and 6 bits?

2

There are 2 best solutions below

2
Tommy On

The quote alleges, close enough to accurately* that the hardware operations to shift by n:

  1. x86 CPUs will shift by n & 31 places (i.e. whatever the value is of the low five bits of n); whereas
  2. PowerPCs will shift by n & 63 places (i.e. the value of the low six bits of n).

* the original 8086 doesn't actually do this, if memory serves. It'll just keep going until it has shifted by a single bit, n times, whatever n might be. But it's also a 45-year-old real-mode-only 16-bit processor so you probably weren't going to target it.

0
Barmar On

They're talking about the second argument to the << or >> operator. The maximum reasonable shift is 31, and that fits into a 5-bit number, so the CPU masks away the higher bits. In other words, on an x86 CPU

uint32_var << shift_amt

is treated as

uint32_var << (shift_amt & 0x1f)

So if you try to shift by 32 bits, instead of shifting everything away, it actually shifts by 0 bits and does nothing.

PowerPC is similar, but the mask is 0x3f, so the shift amount doesn't wrap around until it gets to 64 bits.

Since different CPUs act differently, and they didn't want compilers to have to generate code that checks if the shift amount is too large, they simply declared that this is undefined behavior. It's the programmer's responsibility to avoid shifting by too much.