Home > front end >  Unexpected behaviour from multiple bitwise shift operators in an expression
Unexpected behaviour from multiple bitwise shift operators in an expression

Time:09-12

I noticed that a program that I was writing was not working correctly so I wrote a simple test to check if the problem was the binary shifting. The code is the following:

#include <iostream>
#include <Windows.h>
#include <bitset>

using namespace std;
int main(){
    BYTE byte = 0b10010000; //This is 2^7   2^4 = 144
    cout << "This is the binary number 10010000: " << endl << "Numerical value: " << (unsigned short int) byte << endl << "Binary string: " << bitset<8>(byte) << endl;

    byte = byte << 1;
    cout << "Shifted left by 1 with << 1:" << endl << "Numerical value: " << (unsigned short int) byte << endl << "Binary string: " << bitset<8>(byte) << endl;

    byte = byte >> 5;
    cout << "Shifted right by 5 with >> 5: " << endl << "Numerical value: " << (unsigned short int) byte << endl << "Binary string: " << bitset<8>(byte) << endl;

    byte = 0b10010000;
    byte = (byte << 1) >> 5; //Expect to store 00000001 inside byte
    cout << "But what happens if I do it all in one line? " << endl << "Numerical value: " << (unsigned short int) byte << endl << "Binary string: " << bitset<8>(byte) << endl;
    return 0;
}

Output produced

By running it, the following output is produced:

This is the binary number 10010000:
Numerical value: 144
Binary string: 10010000
Shifted left by 1 with << 1:
Numerical value: 32
Binary string: 00100000
Shifted right by 5 with >> 5:
Numerical value: 1
Binary string: 00000001
But what happens if I do it all in one line?
Numerical value: 9
Binary string: 00001001

What I was expecting

I expected the last messages printed by cout would be:

But what happens if I do it all in one line?
Numerical value: 1
Binary string: 00000001

But surprisingly enough, this wasn't the case.
Can someone explain to me why does this happen? I tried checking microsoft documentation but found nothing.

Additional info: The type BYTE is defined here: https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

CodePudding user response:

You are experiencing the effects of integer promotion.

The operation byte << 1 does not produce an unsigned char, despite byte being of that type. The rationale is that hardware usually cannot perform a number of operations on small types (below a machine word) so C inherited from C the concept of promoting data types in operations to larger types.

So since the result is not 8 bits but, probably, 32 bits, the most significant bit is not shifted out but preserved. After you shift the 32 bit value back and implicitly convert it back to an unsigned char the bit is back in your output.

  • Related