C 结构后增量增加结构 4 个字节?这是为什么

  • 本文关键字:结构 字节 增加 c
  • 更新时间 :
  • 英文 :


我有一个大小为48字节的结构,最近在里面添加了另一个大小为20字节的结构;所以结构的总大小变成了68字节。(所有成员均未签名)

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

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

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

正在发生的事情是结构填充。

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

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

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

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

当您开始读取更大的数据类型时,读取"未对齐"基准的成本可能高于读取对齐的数据:

如果要从地址b01110开始读取 4 个字节(1 个单词),而不仅仅是一个字节,那么您必须读取 2 个单词:

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

编译器"pad"结构以避免此类读取。因为它们很昂贵。正如伍德罗·道格拉斯(Woodrow Douglass)在他们的答案中所建议的那样,你可以强制编译器使用"pack"而不是"pad"。

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

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

所以像这样声明你的 typedef:

typedef struct {
    ...
    ...
    struct s2;
} __attribute__((__packed__)) s1;

最新更新