0

I try to make use of a left shift to identify a setbit using a counter. When I try to left shift var, I found that it is stuck in an infinite loop and only zero gets printed. What is wrong with the following code? Is it even legitimate to make use of a left shift inside a while loop?

#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv)
{
    int var =1;

    while(var<INT_MAX)
    {   
        var = var<<1;
        printf("%d\n", var);        
    }

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
KJ L
  • 115
  • 2
  • 14

2 Answers2

3

It perfectly fine to use a shift operation inside a loop. The problem with your code is that var will never be equal or greater as INT_MAX.

For better understanding let me explain the problem on an 8 bit signed interger and not on a 32 bit signed integer.

You start with the value var = 00000001b (the b indicates that it is a binary number) and the INT_MAX for a 8 bit signed integer would be INT_MAX = 01111111b = 127 (notice that the highest bit is 0, this is because it is the sign bit)

Now if you left shift var you are shifting this single 1 slowly to the right

var << 1 = 00000010b =    2
var << 2 = 00000100b =    4
var << 3 = 00001000b =    8
var << 4 = 00010000b =   16
var << 5 = 00100000b =   32
var << 6 = 01000000b =   64
var << 7 = 10000000b = -128
var << 8 = 00000000b =    0
var << 9 = 00000000b =    0
...

After the seventh shift the 1 bit reached the highest bit, but since we have an 8 bit signed integer we interprete 10000000b not as 128 but as -128 and so var < INT_MAX will always be true.

If you don't know why this happens you may want to read on two complement numbers.

Edit: More formally, like Andrew Henle pointed out: shifting an value outside the range of its type is not defined. The result ot the operation x << y must be equal to x * 2^y and if x * 2 ^y is not representable with the type the result is not defined.

So the table from above looks more like

var << 1 = 00000010b =      2
var << 2 = 00000100b =      4
var << 3 = 00001000b =      8
var << 4 = 00010000b =     16
var << 5 = 00100000b =     32
var << 6 = 01000000b =     64
var << 7 = undef.    = undef.
var << 8 = undef.    = undef.
var << 9 = undef.    = undef.
...
Ackdari
  • 3,222
  • 1
  • 16
  • 33
  • Left-shift of a signed value that is negative is [undefined behavior](https://port70.net/~nsz/c/c11/n1570.html#6.5.7p4): "If E1 has a signed type and nonnegative value, and E1 x 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined." – Andrew Henle Apr 05 '20 at 17:41
2

In this loop

while(var<INT_MAX)
{   
    var = var<<1;
    printf("%d\n", var);        
}

var never can be equal to INT_MAX because only one bit is set in it

int var =1;

that is shifted.

Try the following loop:

while(var<INT_MAX)
{   
    var = ( var << 1 ) + 1;
    printf("%d\n", var);        
} 

Here is a demonstrative program where for simplicity instead of the signed type int there is used the signed type signed char.

#include <stdio.h>
#include <limits.h>

int main(void) 
{
    signed char var = 1;

    while ( var  < SCHAR_MAX )
    {   
        var = ( var << 1 )  + 1;
        printf( "%d\n",  var );        
    }

    return 0;
}

The program output is

3
7
15
31
63
127

And according to the C Standard (5.2.4.2.1 Sizes of integer types <limits.h>)

— maximum value for an object of type signed char
SCHAR_MAX +127 // 2^7 − 1
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335