我还没有找到一个可以回答这种确切行为的问题,而且我只是不知道发生了什么:
我将Windows位图文件(bmp)的内容读取到一个数组中,并在以后使用此数组提取所需的信息:
char biHeader[40];
// ...
source.read(biHeader,40);
// ...
int biHeight = biHeader[8] | (biHeader[9] << 8) | (biHeader[10] << 16) | (biHeader[11] << 24);
此后,
biHeight
显示为-112
,这是完全错误的,因为它应该是400
。因此,我看了一下文件的十六进制转储。读取的内容是:
90 01 00 00
如预期的那样,将字节顺序更改为big endian会得到
0x190
,即十进制400
。如果我将以上代码更改为:
unsigned char biHeader[40];
// ...
source.read((char*)biHeader,40);
// ...
int biHeight = ... (same as before)
...然后我得到了期望值。这里发生了什么?
并且:您将如何读取这些数据?
最佳答案
作为带符号的8位二进制补码整数,0x90
是-112
。将其转换为int
的|
时,将保留其值。由于如果表示形式是二进制补码,则从第七位起的所有位都将置位,因此按位或左移至少八位的值不再更改该值。
作为无符号的8位整数,0x90
的值为144,这是一个正数,没有超出2^7
设置的位。然后,按位或使用biHeader[9] << 8
将值更改为所需的144 + 256 = 400
。
当使用按位运算符时,(几乎)总是使用无符号类型,有符号类型通常会导致令人不愉快的意外(如果移位结果超出范围或向左移负整数,则会导致不确定的行为)。