Somewhat unexpected behaviour from left shift <<

195 views Asked by At

This is a 32-bit MFC application currently running on Windows 10. Compiled with Visual C++ 2013.

std::cout << "sizeof(long long) = " << sizeof(long long) << std::endl;

int rot{ 32 };
long long bits{ (1 << rot) };
std::cout << "bits with variable = " << bits << std::endl;

long long bits2 = (1 << 32);
std::cout << "bits2 with constant = " << bits2 << std::endl;

system("pause");

The size of long long is 8 bytes, sufficient to manage my 32 bits, I was thinking. Here is the output of the debug build:

sizeof(long long) = 8
bits with variable = 1
bits2 with constant = 0
Press any key to continue . . .

And here is the output of the release build:

sizeof(long long) = 8
bits with variable = 0
bits2 with constant = 0
Press any key to continue . . .

So, apparently my single bit is leftshifted into oblivion even with a 64 bit data type. But I'm really puzzled to why the debug build produces different outputs if I shift with a variable as a parameter compared to a constant?

2

There are 2 answers

0
paxdiablo On BEST ANSWER

The expression 1 << rot, when rot is an int, will give you an int result. It doesn't matter if you then place it into a long long since the damage has already been done(a).

Use 1LL << rot instead.


(a) And, by damage, I mean undefined behaviour, as per C11 6.5.7 Bitwise shift operators:

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

As to "why the debug build produces different outputs if I shift with a variable as a parameter compared to a constant", that's one of the vagaries of undefined behaviour - literally anything that's possible is allowed to happen. It's perfectly within its rights to play derisive_laughter.ogg and format your hard disk :-)

4
Bathsheba On

You need a long long type for 64 bits.

The expression 1 << 32 will be evaluated with int types for the operands, irrespective of the type of the variable to which this result is assigned.

You will have more luck with 1LL << 32, and 1LL << rot. That causes the expression to be evaluated using long long types.

Currently the behaviour of your program is undefined as you are overshifting a type when you write 1 << 32. Note also that 1 << 32 is a compile time evaluable constant expression whereas 1 << rot isn't. That probably accounts for the observed difference between using a variable and a constant.