【问题标题】:Nested structure padding - C - 64 bit - linux嵌套结构填充 - C - 64 位 - linux
【发布时间】:2012-12-18 06:18:15
【问题描述】:

我在 C 语言中有以下嵌套结构。(64 位)

    typedef struct {
        int a;
        int b;
        int c;
        struct {
            int ab;
            long bc;
        }
        int d;
    } Test;

I see that,
a = 4 bytes
b = 4 bytes
c = 4 bytes
padding1 = 4 bytes 
inner structure = 16 bytes ( 4 bytes for ab, 4 bytes padding, 8 bytes for bc)
d = 4 bytes
padding2 = 4 bytes

sizeof(Test) 返回 40 个字节。

我的问题:

  1. padding1 -> 为什么这是 4 个字节?这是因为内部结构本身应该对齐吗? (另外,它是否与 8 字节(长)或 16 字节(内部大小)边界对齐。?)

  2. padding2 -> 这是 4 字节填充,因为在结构内部完成了最大对齐(即 8)??

谢谢,

【问题讨论】:

  • 您的代码无法编译。请仅发布经过验证以产生声明结果的真实编译代码。

标签: c 64-bit nested padding structure


【解决方案1】:
  1. padding1 -> 为什么是 4 个字节?这是因为内部结构本身应该对齐吗? (另外,它是否与 8 字节(长)或 16 字节(内部大小)边界对齐。?)

这是因为内部struct应该是8字节对齐的,所以long可以可靠地8字节对齐。

  1. padding2 -> 这 4 字节填充是因为结构内部完成的最大对齐(即 8)吗??

它的存在使得整个struct 的大小是八字节的倍数,因此内部struct 可以在八字节边界上适当地对齐。

在这种特殊情况下,如果匿名struct 成员的处理方式与独立struct 不同,则只需四个字节的填充即可满足对齐要求,但 6.7.2.1

14 结​​构或联合对象的每个非位域成员都以适合其类型的实现定义方式对齐。

禁止这样做。因此,为了减小struct 的大小,程序员需要重新排列它,将奇数个int 成员移动到内部struct 之外(或者使int ab;long bc; 直接成员Test 没有通过匿名struct)。

【讨论】:

  • “只需四个字节的填充就可以满足对齐要求”——不,他们不能。任何包含bc 的结构都必须具有相同的对齐方式,因此内部结构和外部结构都必须是长对齐的,需要对cabd 进行填充。
  • 这是一个匿名结构,它永远不会离开封闭的结构。既然你没有任何独立的示例,为什么编译器不应该将它们视为封闭结构的单独直接成员以用于布局目的?
  • 字段不保证有严格递增的地址吗?
  • @AlanStokes 是的,这是标准对布局做出的少数保证之一。可以移动d 成员的“人”是程序员,而不是编译器。
  • @DanielFischer,匿名与否不应影响布局。不同编译单元之间的布局必须相同,即使字段名称不同。
【解决方案2】:

填充非常依赖于平台和编译器,即使您看到的行为很常见。

通常(这不是 C 标准所说的),编译器对齐结构的成员以减少内存访问次数。在 64 位 x86 的情况下,内存访问始终获取 8 个字节,与 64 位边界对齐。换句话说,如果您访问地址 0x1010AA45 处的 1 个字节,CPU 实际上会从(缓存)内存中获取地址 0x01010AA40 处的 8 个字节。

为了满足这样的规则,如果一个成员是 N 字节长,编译器通常会将 N 舍入到 2 的下一个幂,并在 64 位平台上将成员对齐到这样的大小或 8 字节,无论哪个更小。大多数编译器允许通过#pragma 或配置来调整此类规则。

我相信您的编译器会添加 Padding1,因为它有一个规则将所有结构对齐到 8 字节边界,无论它们有多大。或者,也可以引入它,因为内部结构大于4字节,因此需要对齐到8字节。

Padding2 可能被引入,因为你可以创建一个struct Test 的数组。为了保证所有结构都正确对齐到 8 字节边界 - 而不仅仅是数组中的第一项 - 定义了末尾的填充。

【讨论】:

  • 鉴于实现在 8 字节边界上对齐 long,C 标准要求所有填充...aab 都必须位于包含它们的结构的偏移量 0 , 在ab 之后和abc 之后强制4 个字节,并且必须在d 之前或之后进行填充以进行数组元素对齐。
猜你喜欢
  • 2014-10-12
  • 1970-01-01
  • 2016-12-11
  • 1970-01-01
  • 2017-04-02
  • 2021-10-06
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
相关资源
最近更新 更多