Reputation: 23
I'm shifting some bits and just realized that doing the operation using a variable doesn't have the same result as using a number. See the example below.
int a = 97;
int b = 0;
b = 1 << a;
printf("%d\n", b);
// 2
b = 1 << 97;
printf("%d\n", b);
// 0 - warning: shift count >= width of type [-Wshift-count-overflow]
Upvotes: 2
Views: 221
Reputation: 2995
The undefined behavior is outlined in the C++ standard here.
http://eel.is/c++draft/expr.shift
The behavior is undefined if the right operand is negative, or greater than or equal to the width of the promoted left operand.
You'll get different results depending on compiler and optimization level. If you turn on optimization, the compiler will easily optimize out the first shifting operation and then make it 0 as well.
Why exactly does it act like that though? The x86 instruction for shifting by a variable is SAL (shift-arithmetic-left). You can see the instruction list for bit shifting operations here:
https://c9x.me/x86/html/file_module_x86_id_285.html
The one that would be used in an unoptimized build would be SAL r/m32, CL
. The CL
register is 8 bits, but the processor masks it to 5 bits internally:
The destination operand can be a register or a memory location. The count operand can be an immediate value or register CL. The count is masked to 5 bits, which limits the count range to 0 to 31. A special opcode encoding is provided for a count of 1.
Upvotes: 0
Reputation: 32727
Since the result of a left shift with a right operand larger than the length in bits of the left operand is undefined, any result is possible from the expression.
In the variable case (1 << a
), since a
is 97 (larger than the number of bits in an int
), the most likely results are 1 << (97 % 32)
== 1 << 1
== 2
or 0
, typically depending on how the hardware (CPU) handles these shifts.
With a constant (1 << 97
), the compiler knows you're shifting too far, issues the warning (which is not required), and defines the result as 0
(also not required).
Upvotes: 4
Reputation: 1256
The warning you are seeing is a compile time warning. Now, you can clearly see that your int b
is a 32-bit variable which will be overflown if left-shifted 97 times. So, it's a valid concern. But the compiler can only detect this overflow for the constant number of shifts as it is evaluated during compilation and the compiler immediately knows that it'll overflow.
In case of variable number of shifts, the compiler isn't smart enough to know what value int a
will posses when it'll come down to shifting. So, the compiler leaves it upto you.
Upvotes: 4