D. Leonardo
D. Leonardo

Reputation: 23

Why doesn't the bit-shift of a variable and a number have the same result?

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

Answers (3)

mukunda
mukunda

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

1201ProgramAlarm
1201ProgramAlarm

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

Faisal Rahman Avash
Faisal Rahman Avash

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

Related Questions