"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > Why does the right shift operator (`>>`) in C++ produce unexpected results when shifting by 32 bits?

Why does the right shift operator (`>>`) in C++ produce unexpected results when shifting by 32 bits?

Published on 2024-11-01
Browse:772

Why does the right shift operator (`>>`) in C   produce unexpected results when shifting by 32 bits?
>`) in C produce unexpected results when shifting by 32 bits? " />

Unexpected Behavior of Right Shift Operator (1 >> 32)

In the realm of programming, the right shift operator (>>) is commonly used to perform bitwise operations, particularly to divide an integer by a power of two. However, peculiar behavior can arise when shifting by larger values, as demonstrated by the following C code:

int foo(int a, int b) {
   return a >> b;
}

int bar(uint64_t a, int b) {
   return a >> b;
}

int main() {
    std::cout > 32: " > 32) > (int)32: " > (int)32) 

Surprisingly, the output of this program reveals unexpected results:

foo(1, 32): 1 // Should be 0
bar(1, 32): 0
1 >> 32: 0
(int)1 >> (int)32: 0

The rationale behind these results lies in the internal workings of the CPU and the compiler.

Behavior of foo() Function

In the foo() function, the shift operation is performed without a cast, leading the CPU to perform a logical right shift. On many architectures, the logical right shift is implemented as a >> (b % 32), effectively ignoring the upper bits of b. Therefore, foo(1, 32) results in 1 >> (32 % 32), which evaluates to 1 >> 0, yielding 1.

Why Does Casting to 64-bit Integer Matter?

In the bar() function, a 64-bit unsigned integer is provided, ensuring that the result is guaranteed to be 0 because b (32) is less than the number of bits in the operand (64). However, when b is changed to 64, the result becomes unpredictable and may still yield 1.

Compiler Optimization

In the case of 1 >> 32 and (int)1 >> (int)32, the compiler optimizes these constant expressions at compile-time. The standard specifies undefined behavior for right shifts where the count is negative or greater than or equal to the length of the operand. Since 32 exceeds the length of the operand, the compiler cannot determine the result and outputs 0 as a safe fallback.

CPU-Specific Behavior

The implementation of right shift operations can vary across different CPUs. On x86/x86-64 architectures, the logical right shift is effectively a >> (b % 32 or 64), depending on the mode. However, on ARM processors, the right shift operation guarantees zero for shifts greater than or equal to 32.

Conclusion

When working with right shift operators, it is essential to consider potential undefined behaviors, especially when the shift count exceeds the operand's length. Casting to wider integer types, such as 64-bit integers, can ensure consistent results across different CPUs and compilers.

Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3