2012-12-09 78 views
1

我还没有找到一个问题回答这个确切的行为,不知何故,我只是不明白是怎么回事:C/C++:将char []转换为int失败,将unsigned char []转换为int,原因何在?

我将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。 所以,我看了一下这个文件的hexdump。读出的内容是:

90 01 00 00 

更改字节顺序大端给0x190这是十进制400,符合市场预期。

如果更改上面的代码:

unsigned char biHeader[40]; 
// ... 
source.read((char*)biHeader,40); 
// ... 
int biHeight = ... (same as before) 

...然后我得到的预期值。这里发生了什么?

而且:你会如何读取这些数据?

+0

还有一件事:我真的需要转换为int而不是unsigned int,因为值可能是负值! –

+0

通常BITMAPINFOHEADER是作为一个结构体读取的,其中biHeight在Windows平台上是一个LONG至少 – Chubsdad

+0

我决定不将它作为结构体读取,因为这个头文件有多个版本(结尾有不同的字段)。 作为一个长?根据文件格式定义,这是错误的。 或更具体地说:biHeight由4个字节组成(不多于;因为LONG可能是8个字节) –

回答

4

作为一个有符号的8位二进制补码整数,0x90-112。当它被转换为int|时,其值保留。由于如果表示是二进制补码,所以从第七位开始的所有位都被置位,一个按位或向左移位至少八位的值不会再改变该值。

作为一个无符号的8位整数,0x90的值是144,一个正数,没有超出​​位设置的位数。然后,按位或biHeader[9] << 8将值更改为所需的144 + 256 = 400

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

+0

啊,好的,谢谢。这完全有道理。所以我一直把它读入一个unsigned char []。 –

+0

请注意,代码包含'biHeader [11] << 24',它隐式地将'biHeader [11]'转换为int并将其移位24位。所以C标准没有定义biHeader [11]为128或更多而“int”为32位时的行为。由于此代码需要'int'结果,因此它需要编译器提供有关该情况的行为或特殊处理的保证,或者保证'biHeader [11]'永远不会超过128个。 –

+0

我看到,我的“主要问题”是编译器试图解释这些值。将数组内的值排序(小端到大端)可能更好,然后使用int指针指向内存中的正确位置,对吧? –