为什么要添加填充,如果 char 在 int 之后?

Why padding are added, if char comes after int?

比如有一个结构

struct A
{
char a;
int i;
};

在这种情况下,我们有 a[1 byte] + padding[3 byte] + int[4 byte] = 8.

现在让我们对上面的结构做一点更新,

struct A
{
int i;
char a;
};

在这种情况下,char 在 int 之后,不需要添加填充字节,这意味着 sizeof(A) = 5 字节,但在这种情况下,我也得到了 8 字节的结果。为什么?

好的,这个案例呢

struct s
   {
       int b;
       double c;
       char a;
   };

根据下面给出的逻辑,有一个:size = b[4 bytes] + padding[4 bytes] + c[8] + a[1] + padding[7 bytes to align with double] = 24, 但执行后我得到 16。这怎么可能?

In this case char comes after int and no need to add padding bytes, it means sizeof(A) = 5 byte, but in this case I also get the 8 byte result. Why ?

首先你需要了解为什么需要填充?
Wiki 说:

Data structure alignment is the way data is arranged and accessed in computer memory. It consists of two separate but related issues: data alignment and data structure padding. When a modern computer reads from or writes to a memory address, it will do this in word sized chunks (e.g. 4 byte chunks on a 32-bit system) or larger. Data alignment means putting the data at a memory offset equal to some multiple of the word size, which increases the system's performance due to the way the CPU handles memory. To align the data, it may be necessary to insert some meaningless bytes between the end of the last data structure and the start of the next, which is data structure padding.

为了使大小成为 4 的倍数(int 的对齐方式),第二个片段将填充 3 字节。编译后第二个片段将被填充以正确对齐

struct A
{
    int i;
    char a; 
    char Padding[3]; // 3 bytes to make total size of the structure 8 bytes
};    

编辑:永远记住这两条结构填充的黄金法则:

  • 仅当结构成员后跟[=​​45=]一个具有更大对齐要求的成员或在end 的结构。
  • 最后一个成员用所需的字节数填充,以便结构的总大小应该是任何结构成员的最大对齐的倍数。

如果

struct s
{
    int b;
    double c;
    char a;
};  

对齐将发生为

struct s
{
    int b;             // 4 bytes. b is followed by a member with larger alignment.
    char Padding1[4];  // 4 bytes of padding is needed 
    double c;          // 8 bytes
    char d;            // 1 byte. Last member of struct. 
    char Padding2[7];  // 7 bytes to make total size of the structure 24 bytes 
};   

另请注意,通过更改结构中成员的顺序,可以更改保持对齐所需的填充量。这可以通过 if 成员按降序对齐要求排序来完成。

struct s
{ 
    double c;   // 8 bytes
    int b;      // 4 bytes 
    char a;     // 1 byte. Only last member will be padded to give structure of size 16 
};   

不仅 struct 的每个成员都必须数据对齐,struct 本身也必须与 struct 中最大成员的大小对齐。因此,将填充添加到 struct A,使其大小应为 sizeof isizeof a.

中较大者的倍数

看看 C 常见问题 here

如果要有一个结构数组,则数组中的所有元素必须具有相同的大小和对齐方式;这意味着对于数组中的事物,大小必须是对齐的倍数。拥有一个大小不是对齐倍数的结构唯一有用的情况是,如果它没有直接合并到另一个数组中,而是被用作另一个结构的一部分。这种情况有时确实会发生,但还不够频繁,以至于在语言设计中值得特别注意。

编译器必须在结构末尾添加填充的原因是结构可以是数组的一部分,并且数组的每个元素都必须正确对齐。

您的平台似乎希望 int 对齐到 4 个字节。

如果你声明一个数组 struct A:

struct A array[2];

那么 array[1] 的第一个 int 成员也应该有 4 个字节的对齐。所以编译器将你的 struct A 填充为 8 个字节来实现这一点,而如果它没有添加任何填充并且 sizeof(struct A) 是 5 个字节,array[1] 将不会正确对齐。

(请记住,编译器不能在数组元素之间插入填充,填充必须是数组元素本身的一部分,因为 sizeof array 必须与上面的 sizeof(struct A) * 2 相同例)