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

P

pc

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
 
K

Keith Thompson

pc said:
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.
 
C

crisgoogle

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).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top