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.