Code Yarns ‍👨‍💻
Tech BlogPersonal Blog

C: Shift Operator Mayhem

📅 2004-Dec-20 ⬩ ✍️ Ashwin Nanjappa ⬩ 🏷️ cpp, operators ⬩ 📚 Archive

Came across a puzzling piece of code today. The actual code is confusing, however it basically boils down to this:

#include <stdint.h>

int main()
    uint32_t val   = 1;
    uint32_t count = 32;
    val            = val >> count;

    return 0;

What do you think will be the result in val? Me thought 0. Turned out to be 1.

After further investigation, I found that this was due to a combination of an undefined behaviour in C, vague behaviour of certain IA-32 architecture operations and my ignorance of both.

On examining the code above, it is natural to think that 32 right shifts applied on val would boot out the puny 1 and the result would be 0. Though this is right almost always, it has some exceptions.

From The C Programming Language [1]:

The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression's type.

(Taking val >> count as example, left expression is val and right operand is count.)

So, that explains why the result should not be relied on. But why val is 1? On digging deeper for that, I found that the compiler [2] generated the Intel instruction sar or shr (or it's variants) for the C shift operation. And here lies another nasty info ...

From the IA-32 Intel Architecture Software Developer’s Manual [3]:

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. This masking is done in all operating modes (including the virtual-8086 mode) to reduce the maximum execution time of the instructions.

So, not only is the behaviour in C undefined, on code generated for IA-32 processors, a 5 bit mask is applied on the shift count. This means that on IA-32 processors, the range of a shift count will be 0-31 only.

[1] A7.8 Shift Operators, Appendix A. Reference Manual, The C Programming Language [2] Observed with both Visual C++ and GCC compilers [3] SAL/SAR/SHL/SHR - Shift, Chapter 4. Instruction Set Reference, IA-32 Intel Architecture Software Developer’s Manual