什么情况下结构体不会有填充?

6

sizeof(x)返回2,针对以下结构体

struct s {
    short c;
} x;

但对于结构

struct s {
    short c;
    char a;
} x;

sizeof(x) 返回 4,为什么?

第二个结构体会占用一个填充字节(假设short类型长度��2字节,char类型长度为1字节)。那么第一个结构体不应该占用两个填充字节吗(因此长度为4字节)?


3
你知道填充的目的是什么吗? - StoryTeller - Unslander Monica
当编译器决定时。 - KamilCuk
1
https://stackoverflow.com/questions/47324044/why-is-there-no-padding-in-the-structure-for-only-char-type-members - msc
1
这个问题与你的问题相似,并且有一个很好的回答,涉及到填充。不确定是否重复 https://dev59.com/sYjca4cB1Zd3GeqPyIvt - StoryTeller - Unslander Monica
2
@user3711671:这个想法很简单,就是确保所有元素都对齐到它们的字节大小的倍数地址上。一旦你在结构体中添加一个 int,假设 sizeof(int) > sizeof(short),编译器将不得不填充结构体末尾,使其对齐到 sizeof(int) 的倍数。 - vgru
显示剩余2条评论
2个回答

5
填充的主要用途是根据硬件(或C实现的其他方面)的要求对齐结构成员。有关在结构中布置数据的算法,请参见此答案
回答标题中的问题,即何时结构不需要填充:如果每个成员的对齐需求都是先前所有成员的总大小和所有成员的总大小的除数,则结构不需要填充以进行对齐。(C实现可能仍会添加填充,但这有点不寻常。)
对于您的示例,假设在C实现中,short大小为两个字节,需要两个字节的对齐。按定义,char大小为一个字节,需要一个字节的对齐。
然后,在struct s {short c;}中:
- c放在struct的开头。开头永远不会有填充。 - 如果我们制作这些struct的数组,则下一个struct s将从第一次开始两个字节,并且它的成员 c 仍将位于两个字节的倍数处,因此对齐正确。 - 因此,我们不需要任何填充来使其正常工作。
相比之下,在struct s {short c; char a;}中:
- c放在开头。 - a放在c后两个字节。这很好,因为只需要一个字节的对齐。 - 如果我们不添加任何填充,则struct 的大小为三个字节。然后,如果我们制作这些struct的数组,则下一个struct s将从开始处三个字节开始。 - 在第二个struct s中,成员c将位于三个字节的偏移处。这违反了short的对齐要求。 - 因此,为了使这个struct正常工作,我们必须添加一个字节的填充。这使总大小为四个字节。然后,在这些struct的数组中,所有成员都将处于所需对齐方式的边界上。 即使你仅声明一个结构的单个对象,如struct s {short c; char a;} x;,结构也总是布局为可用于数组。

4

第一个结构体有一个大小为2的元素(假设 short 在您的系统上大小为2)。它就像直接拥有一个短数组。

第二个结构是一个特殊的东西:最好在偶数地址上访问 short 变量。如果我们没有填充,我们会得到以下结果:

struct s arr[5]; // an array
void * a = arr; // needed to reference it

接下来,

  • arr[0].c 存储在地址 a
  • arr[0].a 存储在地址 a + 2 字节。
  • arr[1].c 存储在地址 a + 3 字节!
  • arr[1].a 存储在地址 a + 5 字节!

由于希望将 arr[1].c 存储在偶数地址上,因此需要添加填充位。然后,

  • arr[1].c 存储在地址 a + 4 字节。
  • arr[1].a 存储在地址 a + 6 字节。

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