C ++,读取二进制ifstream时的奇怪行为

时间:2017-10-03 11:03:51

标签: c++ stl binary ifstream file-read

对于我的第一个问题, 我想谈谈用C ++读取二进制文件; 我正在重新编码ID3标记库。

我正在解析作为二进制文件的标头, 前10个字节如下:

ID3    = 3 bytes = constant identifier
0xXXXX = 2 bytes = version (MSB: major version, LSB: minor. eg: 0x0301 = v3.1)
0xXX   = 1 byte  = some flags
4*0xXX = 4 bytes = size

这里是处理该代码的代码:

char          id[4];
uint16_t      version;
uint8_t       flags;
uint32_t      size;
std::ifstream _stream;

_stream = std::ifstream(_filename, std::fstream::binary);

_stream.read(id, 3);
id[3] = 0;
// process id
_stream.read((char *)&version, 2);
// process version
_stream.read((char *)&flags, 1);
// process flags
_stream.read((char* )&size, 4);
// process flags
_stream.close();

除版本外,一切正常。 让我们说它的v3.0(0x0300), 在版本中设置的值是0x03,我会理解文本模式下的这种行为,因为它会将0x00视为字符串的结尾但在这里我用二进制读取。并使用数字格式。

其他奇怪的事情,如果我在2次处理它,我可以使它工作,例如:

uint16_t version = 0;
char     buff;

 _stream.read(&buff, 1);
version = (buff << 8);
 _stream.read(&buff, 1);
version |= buff;

在这种情况下,版本的值为0x0300。

您是否知道为什么第一种方法无法正常工作? 我做错了吗?

无论如何,谢谢你的帮助,

干杯!

2 个答案:

答案 0 :(得分:4)

版本字段不是无符号短字,而是两个无符号字节(主要版本,次要版本)。您应该分别阅读这两个版本号,以免在字典问题中被破坏。

Endianess是特定于平台的。如果你坚持阅读一个结合了主要版本和次要版本的短片,你可以解决它。但最终你会编写不那么干净且易于理解的代码来解决你自己创建的问题。

答案 1 :(得分:1)

这似乎是一个结束问题。那是什么?根据{{​​3}}:

  

字节顺序是指存储在计算机内存或二级存储中时字节排列成较大数值的顺序次序

内存中布局的可视示例:

Wikipedia

big-little-endian

当您将值作为一次性读取时,字节会重新排列,可能是因为它们的写入方式与读取方式不一致。

由于您知道它们在内存中的顺序,因此您应该执行以下操作之一:

  1. 逐字节读取。
  2. 读取值并使用VC ++中的_byteswap_ushort或GCC的__builtin_bswap16交换字节
  3. 读取值并使用Image origin
  4. 交换字节