从二进制文件(大端序)读取到具有多种数据类型的结构体中

Reading from a binary file (big endian) into a struct with multiple data types

提问人:Richard Williams 提问时间:11/4/2022 更新时间:11/4/2022 访问量:323

问:

我有一个二进制格式,它有一堆重复的 32 位整数(按大端顺序排列),类似于这样:

[int a, int b, int c][int a, int b, int c][...]

我简化了很多。struct/binary 文件中实际上有更多的值(但二进制文件都是整数)。我最终想要做的是从文件中读取并创建如下所示的结构:

struct Foo
{
  int a;
  float b;
  float c;
};

其中浮点数只是 b 和 c 的整数值乘以 0.1。

我最初的想法是我应该重载结构?std::ifstream operator>>Foo

我读了这篇关于从 big-endian 流中读取 int 的文章

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

但我不确定如何将其扩展到更大的结构?

我想到的另一种方法是只使用 ,然后遍历结构中的单词并交换字节,但这只会让我得到一个 ints 的结构。infile.read()

我觉得我需要编写一个以 4 个字节读取的流重载。交换它们,如果结构值是浮点数,则将 int 乘以 0.10(不确定我是否需要先转换它)。

我可以用 c 语言轻松完成所有这些工作,但只是想学习 idomatic c++ 的做事方式。

C++ C++11 IOstream

评论

1赞 Jeremy Friesner 11/4/2022
要将 big-endian 32 位整数数据转换为主机 CPU 的 native-endian 格式(无论它是什么),ntohl() 是您的朋友:linux.die.net/man/3/ntohl
0赞 user17732522 11/4/2022
是否使用或任何其他函数作为接口似乎与问题的其余部分无关,该问题与如何实现操作有关。最后一部分在C++中的工作方式与在C中的工作方式相同(只是你使用而不是),第一部分基本上是一个风格问题。operator>>std::ifstream::readfread
0赞 user4581301 11/4/2022
我通常会在新字节中写类似 shifts 和 ORS 的东西。我曾经做过一些复杂的事情,但速度很快,但后来我进行了分析,发现当编译器完成它时,愚蠢的循环也一样快。快速、愚蠢的代码总是比快速复杂的代码更好。如果 的 type 是模板参数,则循环可以根据需要进行扩展,而无需额外的工作。forfor (size_t index = 0; index < sizeof(val); index++)valforval

答:

1赞 Dave Gotwisner 11/4/2022 #1

我只会使用 fread()。然后使用 htonl() 调用循环。由于一切都是 32 位的,如果你想是可移植的,我会使用 int32_t 而不是 int,因为 int 的大小取决于实现。由于数据在技术上是 int32 数据,因此我使结构如下所示:

union wrapper {
    int32_t i;
    float f;
};

然后使你的结构:

struct Foo
{
  int a;
  wrapper b;
  wrapper c;
};

在C++中,我还会做一个静态断言,即 sizeof(union wrapper) == sizeof(int32_t)。

在读取数据之前,我还会调用 stat() 来获取文件的大小并确认它是 struct Foo 的倍数。