【问题标题】:Force C++ structure to pack tightly强制 C++ 结构紧密打包
【发布时间】:2014-02-01 06:22:04
【问题描述】:

我正在尝试读取二进制文件。问题是文件的创建者没有花时间正确地将数据结构与其自然边界对齐,并且所有内容都打包得很紧。这使得使用 C++ 结构读取数据变得困难。

有没有办法强制将struct 打包?

例子:

struct {
    short a;
    int b;
}

上面的结构是8个字节:2个用于short a,2个用于填充,4个用于int b。但是,在磁盘上,数据只有 6 个字节(没有 2 个字节的对齐填充)

请注意,实际的数据结构是数千字节和许多字段,包括几个数组,所以我不想单独读取每个字段。

【问题讨论】:

  • 查看打包结构。请注意,某些架构需要对齐结构才能正确读取它们。
  • en.cppreference.com/w/cpp/language/alignasalignas(0) has no effect?
  • 只需编写代码即可将序列化数据解码为内存中的表示形式。
  • 如果您对此类结构进行字节打包,请在访问该整数值时注意段错误
  • 在你的结构体中指定位域时还要注意字节顺序和域顺序,尤其是当你有任何跨越字节或字边界的域时!

标签: c++ struct


【解决方案1】:

如果您使用的是 GCC,您可以使用struct __attribute__ ((packed)) { short a; int b; }

在 VC++ 上,您可以使用 #pragma pack(1)。这个选项是also supported by GCC

#pragma pack(push, 1)
struct { short a; int b; }
#pragma pack(pop)

其他编译器可能会选择在没有填充的情况下对结构进行紧密打包。

【讨论】:

  • 谢谢。我目前正在使用 GCC 并且有效。不过,如果我们更改编译器,我会留下关于编译指示的评论。
  • 结构继承会发生什么?
  • IIRC 只有这个结构会被紧密包装;继承结构必须再次使用它。如果这是从某些结构继承的,该结构将被视为一种类型,并且它的布局将保持其在其声明中定义的那样。所有这些都是特定于编译器的,因此您应该阅读编译器文档。
  • 这些东西都不起作用。我正在编写一个必须读取所有字段打包在一起的 COFF 二进制文件的系统。 Windows 编译器可以将这些数据读入默认打包的字段中。无论您如何强制,g++ 编译器都无法做到这一点。
  • 我确定它有效; live example。这很可能是一个环境问题。检查您的编译器版本、您传递的标志等。尝试转储您的设置并查看是否有任何关闭值。
【解决方案2】:

您需要使用特定于编译器的非标准指令来指定 1 字节打包。如Windows下:

#pragma pack (push, 1)

问题是文件的创建者没有时间正确地 字节对齐数据结构,一切都被紧紧地打包。

实际上,设计师做了正确的事。填充是标准说可以应用的东西,但它没有说明在什么情况下应该应用多少填充。该标准甚至没有说明一个字节中有多少位。即使您可能认为即使没有指定这些东西,它们在现代机器上仍然应该是相同的合理值,但事实并非如此。例如,在 32 位 Windows 机器上,填充可能是一回事,而在 64 位版本的 Windows 上可能是另一回事。也许它会是一样的——那不是重点。关键是您不知道不同系统上的填充是什么。

因此,通过“打包”,开发人员做了他们唯一能做的事情——使用一些他可以合理确定每个系统都能理解的打包。在这种情况下,通常理解的打包是在保存到磁盘或通过网络发送的结构中不使用填充。

【讨论】:

  • 我的意思是说结构元素的顺序可以安排得更好,这样在许多不同的情况下对齐都会很好。并不是说他们只是简单地将字节打包。
猜你喜欢
  • 2019-10-30
  • 1970-01-01
  • 2011-10-07
  • 2015-07-02
  • 1970-01-01
  • 2017-10-16
  • 1970-01-01
相关资源
最近更新 更多