Search code examples
c++cbit-shift

Why this shift operation plus bitwise works only up to 31?


Why shift operation below works and end up equal? Is there any name for this pattern? I am trying to find out what was going on in the head of the person who wrote this code!

int i = 0x1;
i |= 0x1 << 1;
i |= 0x1 << 2;
i |= 0x1 << 3;
i |= 0x1 << 4;
i |= 0x1 << 5;

int j = 5;

if( ((0x1 << (j + 1)) - 1) == i)
{
    // WHY?
}

I tried to check if this is true for all numbers but only works up to 31.

for (int i = 1; i <= 100; i++) {
    int total_1 = 0x1;
    for (int j = 1; j <= i; j++) {
        total_1 |= 0x1 << j;
    }

    int total_2 = (0x1 << (i + 1)) - 1;
    if (total_2 == total_1) {
    } else {
        cout << i << endl;
        break;
    }
}

UPDATE

Please explain the first part why they would end up equal?


Solution

  • Is there any name for this pattern?

    0x1u << pos (or just 1u << pos) is a pattern for getting a number with only the bit in position pos is set. Using signed 0x1 is usually an anti-pattern.

    i |= 1u << pos is a pattern for setting a bit in position pos of the integer i.

    (1u << pos) - 1 is a pattern for creating a pattern of set bits only in positions lesser than pos.

    Why shift operation below works and end up equal?

    Perhaps it may help to look at intermediate results:

                         // least significant byte
    int i = 0x1;         // 0b0000'0001
    i |= 0x1 << 1;       // 0b0000'0011
    i |= 0x1 << 2;       // 0b0000'0111
    i |= 0x1 << 3;       // 0b0000'1111
    i |= 0x1 << 4;       // 0b0001'1111
    i |= 0x1 << 5;       // 0b0011'1111
    
    int      j = 5;
     0x1 << (j + 1)
     0x1 <<    6         // 0b0100'0000
    (0x1 << (j + 1)) - 1 
     0b0100'0000     - 1 // 0b0011'1111
    

    only works up to 31

    int is probably 32 bits wide on your system. If you left shift a 32 bit 0x1 by 31 or greater, then the behaviour of the program is undefined. If you were to use 0x1u, then you could shift by 31, but 32 and above would be UB.