简体   繁体   中英

Undefined behaviour of right shift (a >> b) when b is greater than the number of bits in a?

Apparently, the behaviour of the right shift operation:

a >> b

is undefined in C and C++ when b >= sizeof(a)*CHAR_BIT (whereas in the normal case, the "new bits" introduced from the left due to the right shift are equal to zero).

Why is this undefined behaviour better than setting the result to zero when b >= sizeof(a)*CHAR_BIT ?

We can get an idea of why languages choose undefined behavior from Why Language Designers Tolerate Undefined Behavior and it says:

This answer came from two general design principles behind C:

  1. The language should impose no unnecessary overhead on the implementation.
  2. It should be as easy as possible to implement C on a wide variety of hardware.

in this specific case what happens when we use a shift count larger than the bit width will depend on the architecture for example as I explain in my answer here :

on some platforms the shift count will be masked to 5 bits for example on an x86 architecture we can see the Intel® 64 and IA-32 Architectures Software Developer's Manual section SAL/SAR/SHL/SHR—Shift in the IA-32 Architecture Compatibility section says:

The 8086 does not mask the shift count. However, all other IA-32 processors (starting with the Intel 286 processor) do mask the shift count to 5 bits, resulting in a maximum count of 31. [...]

So implementing shift for an arbitrary count may be burdensome on some platforms and therefore it is better to leave it undefined behavior.

If we look at the Rationale for International Standard—Programming Languages—C it says:

Unspecified behavior gives the implementor some latitude in translating programs. This latitude does not extend as far as failing to translate the program, however, because all possible behaviors are “correct” in the sense that they don't cause undefined behavior in any implementation.

So there must have been a case or still exists a case where the behavior is not correct and would have bad issues.

Example to why is this undefined behavior better than setting the result to zero.

Typically a CPU has a single instruction that does the shift. If that instruction was required to compare against an upper bound, that would take more circuitry and slow the shifting. Instead, many CPUs' simply use the Least Significant Bits of the shift to determine how much to shift.

// Example - not specified behavior  (assume 32-bit int)
y = 1 << 34;
// same as 
y = 1 << 2;

The first PCs used an 8/16 bit processor that used the least 8 bits to determine the shift, so it indeed would shift in zeros once the shift count was more than the `int width, yet less than 256. The problem with this was that each shift took 1 clock tick. So in a worst-case, the simple shift command could take 255 clock ticks to perform. Of course, after 16 ticks, nothing but 0 were shifted. This long worst case instruction was not interruptible! Thus making that processor's worst case Interrupt latency far worst than the competition. Intel did not make this mistake again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM