【问题标题】:Padding in a C struct with u_long使用 u_long 在 C 结构中填充
【发布时间】:2016-04-13 12:47:45
【问题描述】:

所以我在 C 中有一个这样定义的结构:

struct example {
  int ex1;
  u_long ex2;
  float ex3;
  float ex4;
};

所以示例的所有成员的大小都是 20,但示例的大小是 24,这意味着正在添加填充。我真正不明白的是为什么以及在哪里。

如果我的术语不正确,请原谅,但我认为由于它是 4 字节干净的(即所有成员的大小 % 4 == 0 ),因此不需要添加填充。是因为我正在运行 x86,它需要 8 字节干净,还是只是标准?

然后我真的不知道在哪里添加填充,我会假设围绕 u_long 但我不确定。

【问题讨论】:

  • 您可以使用offsetof 宏来找出答案。
  • 所有类型都没有明确定义的大小。您可能会在字段之间获得额外的填充。
  • 感谢@JoachimPileborg!我最终在这里使用了stackoverflow.com/questions/9788679/… 的建议,因为我很懒,但我不知道宏的存在。

标签: c struct padding


【解决方案1】:

我认为由于它是 4 字节干净的(即所有成员的大小 % 4 == 0 ),因此不需要添加填充。

这不是一个安全的假设。 C 对可以将多少填充添加到 struct 表示或位置几乎没有限制。它根本没有说明何时或为什么。这些选择取决于编译器。

是因为我运行的是 x86,所以它需要 8 字节干净,还是这只是常态?

您假设“8 字节干净”与填充有关。它可能会,但同样,这是一个实施决策。

一般来说,编译器插入填充以确保所有成员可以对齐,以便在structs 数组的每个元素中进行最佳访问。这可能需要在成员之间或末尾或两者之间进行填充。但这仍然是实施方面的考虑。如果您想了解您使用的特定 C 实现如何解决该问题,则需要查阅其文档。

【讨论】:

    【解决方案2】:

    结构体通常也在末尾填充,这样结构体的总大小可以被具有最大对齐的成员所需的对齐方式整除。

    在您的情况下,u_long 需要 8 个字节的对齐,并且在第一个成员的末尾放置 4 个字节,因此它的地址位于 8 个字节的边界上。 struct 的总大小变为 24,因此它最后不需要任何额外的填充。

    末尾的填充可确保在按顺序排列时,第二个元素不会破坏某些成员的对齐方式。

    【讨论】:

    • 或者可能在 u_long 之前,以便它在 8 字节边界上对齐
    • @JohnHascall:这个例子肯定是这样,我只是没有做数学:-)
    • 好吧,我明白了,所以它是决定结构对齐方式的结构成员所需的最高对齐方式。我签入了 gdb(感谢stackoverflow.com/questions/9788679/…),填充在最后。谢谢!
    • “结构体通常也在末尾填充”。是不正确的。在需要正确对齐的任何地方都可以(并且正在)添加填充字节。唯一的例外是在第一个成员之前。
    • @Olaf:你是对的,关于填充的决定完全取决于实现,语言规范并没有强制要求,但是主流平台上的大多数“传统”实现都做了我所做的描述。代码不应该被设计成假设某种布局,但最好知道编译器做某事的原因。
    【解决方案3】:

    这是一个测试,在一台特定的机器上运行,你的结果可能会有所不同:

    $ cat ul.c
    #include <stdio.h>
    
    struct example {
      int ex1;
      unsigned long ex2;
      float ex3;
      float ex4;
    };
    
    struct example ex;
    
    int main ( void ) {
            printf("Size:\t%zd\n", sizeof(ex));
            printf("ex @\t%p\n", &ex);
            printf("ex1 @\t%p\n", &ex.ex1);
            printf("ex2 @\t%p\n", &ex.ex2);
            printf("ex3 @\t%p\n", &ex.ex3);
            printf("ex4 @\t%p\n", &ex.ex4);
            return 0;
    }
    
    $ ./ul
    Size:   24
    ex @    0x600940
    ex1 @   0x600940
    ex2 @   0x600948
    ex3 @   0x600950
    ex4 @   0x600954
    

    此处的填充在 ex1 和 ex2 之间。

    【讨论】:

    • 只是补充:标准保证第一个成员位于偏移量 0。
    猜你喜欢
    • 2015-04-25
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2011-10-21
    • 2023-04-03
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    相关资源
    最近更新 更多