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

C++, weird behavior while reading binary ifstream

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

我正在解析 header 这是一个二进制文件, 前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 视为字符串的结尾,但在这里我正在读取二进制文件。并使用数字格式。

其他奇怪的事情,如果我分两次处理它就可以让它工作,例如:

uint16_t version = 0;
char     buff;

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

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

你知道为什么第一种方法不能正常工作吗? 我做错了什么吗?

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

干杯!

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

Endianess 是特定于平台的。如果您坚持阅读结合了主要版本和次要版本的单个短片,则可以解决它。但最终您编写的代码不够清晰易懂,无法解决您自己创建的问题。

这似乎是字节顺序问题。那是什么?根据 Wikipedia:

Endianness refers to the sequential order in which bytes are arranged into larger numerical values, when stored in computer memory or secondary storage

内存中布局的可视化示例:

Image origin

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

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

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