After compiling the code below, i got a weird result, a =1 while b =0. Could anyone explain what's going on behind the scene?
#include<iostream>
using namespace std;
int main(){
int n=32;
int a=1<<n; //turns out a=1
int b=1<<32; //turns out b=0
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
Because you are invoking undefined behavior. Shifting more bits than exist in the type is not defined to have any particular behavior.
See http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html?m=1
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.
The standard does not define, or rather, it defines it as "undefined behaviour", what happens in the case left shift beyond the size of the integer type. [The reason for this undefined behaviour is that different hardware may or may not behave the same given, for example, a 32-bit shift to the left].
In the first case [at least without optimization], the compiler generates instructions to calculate 1 << 32
- which on x86 turns into 1 << (32 & 31)
which is the same as 1 << 0
- thus you get 1.
In the second case, the compiler will calculate the value itself, which turns into an overflow, and gives zero.
It's quite likely (but not certain) that if you change the compiler options to optimize the code, it gives zero for both cases. And you are going to get the behaviour you want if you were to do a loop of smaller shifts (although you may find "intersting" behaviour with the fact that the number turns negative, so best to use unsigned for all shift operations, really).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With