Velocity Reviews > left shift operator behaves like left rotate when the operand is a variable.

# left shift operator behaves like left rotate when the operand is a variable.

pc
Guest
Posts: n/a

 06-08-2011
Below is a snippet of code and the result (compiler version also
mentioned). I fail to understand why the left shift operator behaves
as if it were the left rotate operator when the operand is a variable.

\$ cat test.c
#include <stdio.h>
int main(void)
{
unsigned int a = 32, b = 33;
printf("with constants 1 << 32 = %u, 1 << 33 = %u\n", 1<<32,
1<<33);
printf("with variables 1 << 32 = %u, 1 << 33 = %u\n", 1<<a, 1<<b);
return 0;
}
\$ gcc test.c
test.c: In function 'main':
test.c:6:5: warning: left shift count >= width of type
test.c:6:5: warning: left shift count >= width of type
\$ ./a.out
with constants 1 << 32 = 0, 1 << 33 = 0
with variables 1 << 32 = 1, 1 << 33 = 2
\$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

Keith Thompson
Guest
Posts: n/a

 06-08-2011
pc <(E-Mail Removed)> writes:
> Below is a snippet of code and the result (compiler version also
> mentioned). I fail to understand why the left shift operator behaves
> as if it were the left rotate operator when the operand is a variable.
>
> \$ cat test.c
> #include <stdio.h>
> int main(void)
> {
> unsigned int a = 32, b = 33;
> printf("with constants 1 << 32 = %u, 1 << 33 = %u\n", 1<<32,
> 1<<33);
> printf("with variables 1 << 32 = %u, 1 << 33 = %u\n", 1<<a, 1<<b);
> return 0;
> }

[snip]

I'm guessing unsigned int is 32 bits in your implementation; it would
have been helpful to tell us that.

C99 6.5.7p3:

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.

So if you shift a 32-bit number by 32 bits, the implementation isn't
required to behave consistently.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Guest
Posts: n/a

 06-08-2011
On Jun 8, 11:05*am, pc <(E-Mail Removed)> wrote:
> Below is a snippet of code and the result (compiler version also
> mentioned). I fail to understand why the left shift operator behaves
> as if it were the left rotate operator when the operand is a variable.
>
> \$ cat test.c
> #include <stdio.h>
> int main(void)
> {
> * * unsigned int a = 32, b = 33;
> * * printf("with constants 1 << 32 = %u, 1 << 33 = %u\n", 1<<32,
> 1<<33);
> * * printf("with variables 1 << 32 = %u, 1 << 33 = %u\n", 1<<a, 1<<b);
> * * return 0;}
>
> \$ gcc test.c
> test.c: In function 'main':
> test.c:6:5: warning: left shift count >= width of type
> test.c:6:5: warning: left shift count >= width of type
> \$ ./a.out
> with constants 1 << 32 = 0, 1 << 33 = 0
> with variables 1 << 32 = 1, 1 << 33 = 2
> \$ gcc --version
> gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

Read the warning that was given to you!!

Shifting by greater-than-or-equal-to the width of the shifted type
is undefined behaviour, so your program could have printed anything.

What's actually happening to cause your specific output is probably
this:

When you use constants, the compiler is "smart" enough to realize
that you're shifting the bits right off the end, and so the result
is known at compile time to be zero. When the shift is variable
however,
the compiler emits actual shift instructions. A common low-level
implementation of a shift, down at the CPU level, actually masks out
anything beyond the 5 bits required to give you a 31-bit shift.
So if the shift value is 32, you actually get a shift of zero;
if it's 33, you get a shift of 1.

Again however, the code you wrote has undefined behaviour, so anything
can happen. In particular, in this case the output will almost
certainly be very dependent upon optimization levels, and perhaps
other "meaningless" changes such as whether a or b are declared
const (that last bit is just a wild guess, but entirely possible).