Search code examples
cwhile-loopoperatorsbit-shiftunsigned-integer

Can we left shift a value inside a while loop?


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;
}

Solution

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