Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Left shift bits in c

Tags:

c

bit-shift

I have been making some stupid test about bits manipulation, and I found this issue. I execute this code:

int main(){
  unsigned int i;
  for (i=1; i<34; i++)
  {
    unsigned long temp = i;
    unsigned long mul = 1;
    unsigned long val;
    unsigned long one = 1;

    // Way 1
    while (temp--)
      mul = mul << one;

    // Way 2
    val = (one<<i);

    printf(" \n 1<<%i \n mul: 0x%X , val: 0x%X\n",i, mul, val); 
  }
}

Of course, I know that when i>31, an overflow will be produced. I think that both parts of code (way1 and way2) should output the same result. But I get this (at the end):

 /* ... correct results from i=1 to i=31 ... */
 1<<30 
 mul: 0x40000000 , val: 0x40000000 

 1<<31 
 mul: 0x80000000 , val: 0x80000000 

 1<<32 
 mul: **0x0** , val: **0x1** 

 1<<33 
 mul: **0x0** , val: **0x2**

Why, if both instructions are left shifts, the program produces different outputs? It seems that the part way2 produces a round shift, but I don't know why, I really think that "mul" gets always the correct value.

I compile under a Intel 32bits machine, gcc version 4.4.7

like image 342
Alexi Avatar asked Jun 21 '16 15:06

Alexi


2 Answers

Probably because that's undefined behaviour? According to §6.5.7:

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.

like image 119
Aif Avatar answered Oct 18 '22 06:10

Aif


In case of

val = (one<<i);

when i gets greater than or equal to 32, the behavior is undefined.

 

However, in case of

while (temp--)
   mul = mul << one;

for shifts more than 32, it will shift zero and the result is defined (zero).

like image 29
masoud Avatar answered Oct 18 '22 05:10

masoud