我还没有找到一个可以回答这种确切行为的问题,而且我只是不知道发生了什么:

我将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

当使用按位运算符时,(几乎)总是使用无符号类型,有符号类型通常会导致令人不愉快的意外(如果移位结果超出范围或向左移负整数,则会导致不确定的行为)。

09-07 08:35