C结构体的数据对齐

3
以下结构体中所有字段的字节偏移量在CS:APP书籍的第3.45问题中存在问题。
struct {
  int    *a;
  float  b;
  char   c;
  short  d;
  long   e;
  double f;
  int    g;
  char   *h;
} rec;

这里是书中给出的答案,它为c添加了三个字节的填充,为d添加了两个字节的填充,为g添加了四个字节的填充。
field  size  offset
-----  ----  ------
a      8     0
b      4     8
c      1     12
d      2     16
e      8     24
f      8     32
g      4     40
h      8     48

这是我的解决方案,只给c添加了一字节的填充,并给g添加了四字节的填充。
field  size  offset
-----  ----  ------
a      8     0
b      4     8
c      1     12
d      2     14
e      8     16
f      8     24
g      4     32
h      8     40

那么,我的解决方案有什么问题呢?它似乎符合对齐规则(编辑*这里的“规则”只是我自己总结的简化概念,不完整或通用),所有对象的偏移量都是对象大小的倍数。

非常感谢任何解释。


1
问题中提供了对齐规则吗? - Deepstop
3
首先,请不要在C问题上标记C++。其次,对于对齐没有标准规则。任何表明有特定答案的书籍都必须参考针对特定体系结构、特定编译器版本和特定编译器选项编译的特定代码片段。 - Thomas Jager
3
事实上,使用Apple LLVM 10.0.1和Clang 1001.0.46.4构建x86-64的结构布局与您所展示的相同,而不是书中所示。如果对齐规则确实是每个对象必须对齐到其大小的倍数,那么这本书是错误的。 - Eric Postpischil
@ThomasJager:书中的练习明确提出了特定情况和特定规则,而不是教授C标准通常允许什么。 - Eric Postpischil
如果sizeof(short)为4,则该书是正确的。 - Antti Haapala -- Слава Україні
2个回答

3
答案取决于编译器、平台和编译选项。以下是一些示例: enter image description here https://godbolt.org/z/4tAzB_ 这本书的作者恐怕不理解这个主题。

很酷的网站!非常有帮助! - Tetrau

3

给定所示对象的大小和对齐规则,每个对象必须对齐到其大小的倍数,当使用仅需要对齐的填充时布置结构,则偏移应如Tetrau的解决方案所示。该书的解决方案是错误的。

Tetrau解决方案中显示的偏移实际上是Apple LLVM 10.0.1 with Clang 1001.0.46.4为x86-64编译而产生的偏移。程序输出如下:

0
8
12
14
16
24
32
40
48
struct foo {
  int    *a;
  float  b;
  char   c;
  short  d;
  long   e;
  double f;
  int    g;
  char   *h;
} rec;


#include <stddef.h>
#include <stdio.h>


int main(void)
{
    printf("%zu\n", offsetof(struct foo, a));
    printf("%zu\n", offsetof(struct foo, b));
    printf("%zu\n", offsetof(struct foo, c));
    printf("%zu\n", offsetof(struct foo, d));
    printf("%zu\n", offsetof(struct foo, e));
    printf("%zu\n", offsetof(struct foo, f));
    printf("%zu\n", offsetof(struct foo, g));
    printf("%zu\n", offsetof(struct foo, h));
    printf("%zu\n", sizeof rec);
}

注意

对象需要按其大小的倍数对齐的规则对于这个练习来说是可以的,但需要注意的是,这不是一个普遍的规则。一台机器可能有一个8字节的对象,但只有4字节宽的总线和其他内存访问特性,因此它最多只关心任何对象的4字节对齐。或者一个结构体成员可能是另一个大小为9字节的结构体(例如struct bar { char x[9]; }),但其对齐要求不是9字节。


甚至可以使用1字节对齐(8位微控制器)。 - 0___________
好的,我在问题中提到的规则是从书中原始概念的缩写版本(可能太短了)。填充值因不同平台、编译器而异,正如 @P__J__ 和 CS:APP 所示,建议在 Linux、x86-64 上使用 GCC,但书中给出的答案还是有些奇怪。我也查过书的勘误表,但没有发现任何错误。 - Tetrau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接