【问题标题】:C/C++: Conversion of char[] to int fails, unsigned char[] to int works, why?C/C++:char[] 到 int 的转换失败,unsigned char[] 到 int 有效,为什么?
【发布时间】:2012-11-27 00:55:05
【问题描述】:

我还没有找到回答这种确切行为的问题,不知何故我就是不明白发生了什么:

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

...然后我得到预期值。这是怎么回事?

还有:您将如何读取这些数据?

【问题讨论】:

  • 还有一件事:我真的需要转换为 int 而不是 unsigned int 因为值可能是负数!
  • 通常 BITMAPINFOHEADER 被读取为一个结构,其中 biHeight 至少在 windows 平台上是一个 LONG
  • 我决定不将其作为结构读取,因为此标头有多个版本(末尾有不同的字段)。作为一个长?根据文件格式定义,这是错误的。或者,更具体地说:biHeight 由 4 个字节组成(而不是更多;因为 LONG 可能是 8 个字节)

标签: c++ c serialization file-io type-conversion


【解决方案1】:

作为有符号 8 位二进制补码整数,0x90-112。当将 | 转换为 int 时,其值将被保留。由于如果表示是二进制补码,则从第 7 位开始的所有位都已设置,因此按位或将值左移至少 8 位不会再改变值。

作为一个无符号的 8 位整数,0x90 的值为 144,这是一个正数,没有超出 2^7 位集的位。然后,按位或 biHeader[9] &lt;&lt; 8 将值更改为所需的 144 + 256 = 400

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

【讨论】:

  • 啊,好的,谢谢。这完全有道理。所以我一直把它读成一个无符号字符[]。
  • 请注意,代码中包含biHeader[11] &lt;&lt; 24,它将biHeader[11]隐式转换为int并将其移动24位。所以 C 标准没有定义 biHeader[11] 为 128 或更多且 int 为 32 位时的行为。由于此代码需要 int 结果,因此它需要编译器提供有关此情况的行为或特殊处理的保证,或者保证 biHeader[11] 永远不会为 128 或更大。
  • 我明白了,我的“主要问题”是编译器试图解释这些值。最好对数组中的值进行排序(从小端到大端),然后使用 int 指针指向内存中的正确位置,对吧?
  • @DanielOertwig 我不这么认为。使用int* 可能会出现对齐问题,有些平台是大端,有些是小端。 IMO 最好使用 unsigned ints 进行移位(或 uint32_t/uint_least32_t 以确保将 8 位值移位 24 位不会溢出)。喜欢(uint32_t)biHeader[8] | ((uint32_t)biHeader[9] &lt;&lt; 8) | ...。现在问题仍然存在,如果值超出int 范围[通常当且仅当biHeader[11] 中的2^7 位被设置时],到int 的转换是实现定义的。如果biHeight 的类型可以是无符号的就好了
  • 如果必须是int,从unsigned intint 的典型转换只是对位的重新解释,这样就可以了(但不是完全可移植的)。跨度>
猜你喜欢
  • 2012-05-06
  • 2015-01-05
  • 2013-09-15
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 2012-04-28
  • 2015-07-11
相关资源
最近更新 更多