1

我有一个大小为 48 字节的结构,最近在其中添加了另一个大小为 20 字节的结构;所以结构的总大小变成了 68 字节。(所有成员都是无符号整数)

typedef struct{
           ...
           ...
           unsigned long long a1;
           struct s2
           }s1 ;

S1结构是一个数组;如果 s1 使用 s1++ 递增,则观察到 s1 递增 72 个字节而不是 68 个字节。令人惊讶的是,如果结构 s2 从 s1 中删除,一切正常,即 s1 会增加 48 个字节。任何有关原因的指示都会有所帮助。

4

3 回答 3

3

你没有说你正在使用什么编译器或平台,但很可能编译器正在添加对齐字节以使结构在 8 字节边界上对齐。这很常见。

于 2012-05-24T14:25:41.010 回答
1

正在发生的是结构填充。

它由编译器完成,以确保元素位于对齐的内存地址。

您可以在此处阅读有关 x86/x86_64 中“对齐”的更多信息。

现在,为什么它们应该位于对齐的地址?(以 4 字节 WORD 为例):机器以“字”的形式从内存中访问数据。对于一个 4 字节的 WORD,这意味着要从地址读取单个字节b11001110,您需要读取 4 个字节(地址中的最后 2 位基本上在读取时被忽略),然后选择您需要的字节一次WORD 在 CPU 中:

| b11001100 | b11001101 | b11001110 | b11001111 |    <- all four loaded at once
                        \           /
                        only one used

当您开始读取更大的数据类型时,读取“未对齐”数据可能比读取对齐数据成本更高:

如果您想读取从 address 开始的 4 个字节(1 个字)b01110,而不是一个字节,那么您必须读取 2 个字:

        first load             second load
/                       \/                      \
|01100|01101|01110|01111|10000|10001|10010|10011|
            \                       /
               unaligned data read

编译器“填充”结构以避免此类读取。因为它们的成本很高。正如 Woodrow Douglass 在他们的回答中所建议的那样,您可以强制编译器“打包”而不是“填充”。

还有一件事:有些架构甚至不可能进行未对齐的负载。在此类机器上,操作系统通常会捕获在未对齐加载期间引发的异常,然后以某种方式模拟加载(例如,通过执行多个对齐加载)。

于 2012-05-24T14:48:58.683 回答
-1

这是64位机器吗?72 字节是 64 位字边界。您的编译器正在调整您的结构。在 gcc 中,如果你用 声明你的结构__attribute__((__packed__)),你可以避免这种情况。

所以像这样声明你的typedef:

typedef struct {
    ...
    ...
    struct s2;
} __attribute__((__packed__)) s1;
于 2012-05-24T14:26:14.597 回答