I must be absolutely crazy here, but gcc 4.7.3
on my machine is giving the most absurd result. Here is the exact code that I'm testing:
#include <iostream>
using namespace std;
int main(){
unsigned int b = 100000;
cout << (b>>b) << endl;
b = b >> b;
cout << b << endl;
b >>= b;
cout << b << endl;
return 0;
}
Now, any number that's right shifted by itself should result in 0 (n/(2^n) == 0
with integer divide, n>1
, and positive/unsigned), but somehow here is my output:
100000
100000
100000
Am I crazy? What could possibly be going on?
You are invoking undefined behavior if you shift greater than the bit length of the left operand, the draft C++ standard section
5.8
Shift operators paragraph 1 says(emphasis mine):Interesting to note that both
gcc
andclang
may generate a warning for this code if the shift amount if a literal:or if
b
is a const, the warning forgcc
is as follows:as MSalters points out in the comments to the question, we may not be able to even rely on this warning since this is undefined behavior, which is consistent with the standards note on undefined behavior in the terms and definitions section which says:
Platform specific details
A potential explanation for the apparent lack of a shift in the example code may be because on some platforms the shift count will be masked to
5 bits
for example on anx86
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:In C++ as in C, shifts are limited to the size (in bits) of the value shifted. For instance, if unsigned int is 32 bits, then a shift of more than 31 is undefined.
In practice, a common result is that the 5 least-significant bits of the shift amount are used and the higher order bits are ignored; this is due to the compiler producing a machine instruction which does exactly that (eg SHR on x86).
In this case, the shift value is
100000
(decimal) which happens to be11000011010100000
in binary - the lower 5 bits are zero. So, you're effectively getting a shift by 0. You shouldn't rely on this however; technically, what you're seeing is undefined behaviour.References:
For C, N1570 section 6.5.7:
For C++, N3690 section 5.8 "[expr.shift]":
N1570 is a draft, nearly identical to the released ISO C11 standard; this clause has been pretty much the same since the 1989 ANSI C standard.
N3690 is a recent draft of the C++ standard; I'm not sure whether it's the best one to use, but again, this clause hasn't changed.