当结构中的整数后跟大小大于整数的字符时,填充不适用于结构中的整数

Padding not applied on integer in a struct when it is followed by a char of size bigger than integer

我正在检查一些结构的大小。根据填充规则,我期待不同的结果。当我有一个大小在 4 到 8 之间的字符时,我看到填充应用于最大大小为 8 的字符,但填充不适用于前面的整数或结构的最后一个 integer/variable。

这里的主要问题是为什么当整数后跟大于 4 的字符时不对整数应用填充?

如果整数仍然使用 4 个字节,对 char 应用填充以达到 8 个字节是什么意思?

下面,您可以在评论中看到我的问题的代码:

#include <stdio.h>

typedef struct {
    int i;      
    char str[3]; //padding of 1
    int f;
} stru_10;

//size is 4+4+4 = 12

typedef struct {
    int i;       //why no padding applied here?
    char str[7]; // padding of one
    int f;       //why no padding applied here?
} stru_11;

//Actual result : size is 16. Why no padding on integers?

typedef struct {
    int i;       //why no padding applied here?
    char str[9]; // padding of 3
    int f;       //why no padding applied here?
} stru_12;

//Actual result : Size is 20. Why no padding on integers?

typedef struct {
    int i;        //why no padding applied here?
    char str[5];  // padding of 3
    int f;        //why no padding applied here?
} stru_13;

//Actual result : Size is 16. Why no padding on integers?

typedef struct {
    int i;        
    char c;  // padding of 3
    int f;        
} stru_14;

//Actual result. Size is 12 as expected.

typedef struct {
    int i;    // padding of 4    
    char *c;  // padding of 3
    int f;    //padding of 4  
} stru_15;

//Actual result. Size is 24 as expected(8*3).

int main(void) {

    printf("Size of stru_10 is %d\n",sizeof(stru_10)); //12
    printf("Size of stru_11 is %d\n",sizeof(stru_11)); //16
    printf("Size of stru_12 is %d\n",sizeof(stru_12)); //20
    printf("Size of stru_13 is %d\n",sizeof(stru_13)); //16
    printf("Size of stru_14 is %d\n",sizeof(stru_14)); //12
    printf("Size of stru_15 is %d\n",sizeof(stru_15)); //24

    return 0;
}

but padding is not applied for the preceding integer or for the last integer/variable of the struct.

为什么会这样?

不要把它想成"padding"。大多数情况下发生的事情是这样的:

基本数据类型(整数、浮点数、双精度数等)需要在内存中正确对齐,以便 CPU 可以有效地读取它们(或者甚至因为某些 CPUs当您读取未正确对齐的数据时,只会使您的程序崩溃)。即使它们是结构的一部分,这也适用。为了实现这种一致性,几乎每个人都遵循这个模型:

  • 每个结构成员在结构内按其自然对齐方式对齐。
  • 结构的大小四舍五入为其最严格对齐的成员所需对齐的倍数。
  • 数组的对齐与其元素的对齐相同。

C 标准允许的远不止于此,但实际上几乎每个人都这样做,因为它解决了所有数据类型、结构和结构数组的所有对齐问题。除非你有一个非常奇怪的 CPU.

在您的示例中,int 的对齐要求最有可能是 4 和 1 字符。根据以上规则,您可以了解元素的布局方式。你所说的 "padding" 只是正确对齐后剩下的位。

让我们举一个例子。

typedef struct {
    int i;       //why no padding applied here?
    char str[7]; // padding of one
    int f;       //why no padding applied here?
} stru_11;

i需要在4处对齐。它在偏移量0处。(0 % 4) == 0,所以对齐很好。 str 需要在 1 处对齐。结构中的第一个空闲偏移量是 4。(4 % 1) == 0,这样就足够了。 str 放在偏移量 4。f 需要在 4 处对齐,结构中的第一个空闲偏移量是 11。(11 % 4) == 3,所以这还不够好。但是 12 已经足够了,让我们把 f 设置为 12。结构的大小现在是 16,结构的最大成员的对齐是 4,(16 % 4) == 0,这满足了结构成员对齐的所有要求,我们可以将结构保留为 16 大小,无需进一步对齐或填充。

请注意,我上面写的不是语言标准强制要求的。布置结构成员的机制是称为 ABI(应用程序二进制接口)的其他标准的一部分,每个操作系统 + CPU 组合都可以有自己的 ABI。大多数 ABI 都这样定义要完成的事情,因为这是最简单和最有效的方法,但如果有疑问,您需要从 OS+CPU 组合中找到特定的文档(如果它完全存在)。