强制C++结构紧密包装

问题描述 投票:0回答:3

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

有没有办法强制

struct
挤紧?

示例:

struct {
    short a;
    int b;
}

上面的结构是8个字节:2个用于

short a
,2个用于填充,4个用于
int b
。然而,在磁盘上,数据只有 6 个字节(没有用于对齐的 2 个字节的填充)

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

c++ struct
3个回答
78
投票

如果您使用的是 GCC,您可以这样做

struct __attribute__ ((packed)) { short a; int b; }

在 VC++ 上你可以做

#pragma pack(1)
。此选项 GCC 也支持

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

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


17
投票

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

#pragma pack (push, 1)

问题是文件的创建者没有花时间正确地 字节对齐数据结构,所有内容都紧密包装。

其实,设计师做的是对的。标准说可以应用填充,但没有说明在什么情况下应该应用多少填充。标准甚至没有说明一个字节有多少位。尽管您可能认为即使未指定这些内容,它们在现代机器上仍应具有相同的合理值,但这根本不是事实。例如,在 32 位 Windows 计算机上,填充可能是一回事,而在 64 位版本的 Windows 上,填充可能是另一回事。也许会是一样的——这不是重点。关键是你不知道不同系统上的填充是什么。

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


0
投票

与编译器/平台无关的方法是对元素使用字节数组,因为无论如何你都需要明确它们的大小。

所以代替:

struct __attribute__ ((packed)) {
    short a;
    int b;
}

您可以使用:

struct {
    char a[2];
    char b[4];
}

char
的对齐大小保证是一个字节,因此这将打包。当然,您必须明确转换为
short
int
等类型。这是否是净收益留给读者作为练习。

© www.soinside.com 2019 - 2024. All rights reserved.