为什么编译器将填充添加到已经4字节对齐的结构中?

时间:2017-08-02 14:30:45

标签: c gcc

此问题已使用多个32位体系结构重现

我有以下结构,其中所有数据成员大小的总和是76字节:

typedef struct
{


    uint32_t unused_32;

    //Unrolled arrays
    uint8_t ar1_1;
    uint8_t ar1_2;

    uint8_t ar2_1;
    uint8_t ar2_2;

    uint8_t ar3_1;
    uint8_t ar3_2;

    uint8_t ar4_1;
    uint8_t ar4_2;
    uint8_t ar4_3;
    uint8_t ar4_4;
    uint8_t ar4_5;
    uint8_t ar4_6;


    uint8_t ex1;
    uint8_t ex2;
    uint8_t ex3;
    uint8_t ex4;
    uint8_t fsi_1;
    uint8_t fsi_2;
    uint8_t fsi_3;
    uint8_t fsi_4;


    uint64_t ex5;
    uint64_t ex6;
    uint64_t Unused_1;
    uint64_t Unused_2;
    uint64_t Unused_3;
    uint64_t Unused_4;

    uint32_t Crc;       

} testStruct;

但是,当我在struct上执行sizeof()时,我得到了80个字节,而我却无法弄清楚原因。当我将预处理器设置为使用“#pragma pack(1)”选项并执行sizeof()时,它返回76个字节,表示编译器正在添加填充。

我打印出结构中每个数据成员的地址,所有内容都按顺序排列在内存中,没有“漏洞”。我还在结构体之前添加了一个32位整数的初始化并打印出它的地址,它在结构的第一个数据库之前出现,表明正在添加的填充在最后。

76字节已经是4字节对齐,为什么编译器在结构的末尾添加额外的4个字节以使其为80字节?

3 个答案:

答案 0 :(得分:6)

来自GCC documentation

  

请注意,ISO C标准要求任何给定结构或联合类型的对齐至少是所讨论的结构或联合的所有成员的对齐的最低公倍数的完美倍数。 / p>

换句话说,因为你的struct包含uint64_t类型的成员(对齐到8个字节),所以struct本身必须与8字节边界对齐。

答案 1 :(得分:2)

由于OP能够使用#pragma pack(1),一个特定于实现的指令,它意味着结构的大小可以打包到76个字节而不是OP平台上的80个字节。

使用这样的打包,testStruct数组肯定会导致uint64_t成员出现在非八进制地址上。通过用4填充结构,testStruct的数组,从八进制地址开始,每个元素中的所有uint64_t成员对齐以获得潜在的最佳代码/速度。

这是编译器对优化,代码,速度和内存使用进行的常见折衷。

大多数编码任务不应该采用压缩结构。

对于需要精确布局的代码,需要像#pragma pack(1)这样的实现指令或可移植性,需要另一种非struct方法。

答案 2 :(得分:0)

编译器使用4字节边界直到fsi_4,然后在“uint64_t”的声明开始时使用8字节边界,这就是为什么你得到80字节的总大小。