I haven’t found a question answering this exact behaviour, and somehow I just don’t understand what is going on:
I read the contents of a Windows Bitmap File (bmp) into a array and use this array later to extract required information:
char biHeader[40];
// ...
source.read(biHeader,40);
// ...
int biHeight = biHeader[8] | (biHeader[9] << 8) | (biHeader[10] << 16) | (biHeader[11] << 24);
After this, biHeight shows as -112 which is totally wrong because it should be 400.
So, I took a look at a hexdump of the file. The contents read are:
90 01 00 00
Changing the byte order to big endian gives 0x190 which is 400 in decimal, as expected.
If I change above code to:
unsigned char biHeader[40];
// ...
source.read((char*)biHeader,40);
// ...
int biHeight = ... (same as before)
… then I get the expected value. What is going on here?
And: How would you read this data?
As a signed 8-bit two’s complement integer,
0x90is-112. When that is converted tointfor the|, its value is preserved. Since all bits from the seventh on are set if the representation is two’s complement, a bitwise or with values shifted left by at least eight bits doesn’t change the value anymore.As an unsigned 8-bit integer, the value of
0x90is 144, a positive number with no bits beyond the2^7bit set. Then, a bitwise or withbiHeader[9] << 8changes the value to the desired144 + 256 = 400.When working with bitwise operators, (almost) always use unsigned types, signed types often lead to unpleasant surprises (and undefined behaviour if the shift result is out of range or a negative integer is shifted left).