编译器会秘密增加struct的对齐吗?

wan*_*907 0 c c++ struct memory-alignment

我有一个8字节对齐的结构,但是当我连续定义这种类型的某些变量但不在数组中时,它似乎是16字节对齐.我的问题是,编译器是否为某种目的增加了它的对齐?

我的测试代码是:

#include <stdio.h>
#include <stdint.h>
struct a{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;

int main(){
    printf("%lx\n", (uintptr_t)&a1);
    printf("%lx\n", (uintptr_t)&a2);
    printf("%lx\n", (uintptr_t)&a3);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

601030
601050
601070
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 5

在64位Unix机器上(运行macOS Sierra 10.12.6的Mac,使用GCC 7.1.0),此代码:

#include <stdio.h>
#include <inttypes.h>
struct a
{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;
struct a a4[4];

int main(void)
{
    printf("sizeof(struct a) = %zu\n", sizeof(struct a));
    printf("a1 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a1);
    printf("a2 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a2);
    printf("a3 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a3);
    for (int i = 0; i < 4; i++)
        printf("a4[%d] = 0x%.16" PRIXPTR "\n", i, (uintptr_t)(void *)&a4[i]);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

产生这个结果:

sizeof(struct a) = 24
a1 = 0x0000000106776020
a2 = 0x0000000106776040
a3 = 0x0000000106776060
a4[0] = 0x0000000106776080
a4[1] = 0x0000000106776098
a4[2] = 0x00000001067760B0
a4[3] = 0x00000001067760C8
Run Code Online (Sandbox Code Playgroud)

请注意,三个独立结构布局在32字节边界上,但数组中的那些结构布局在24字节边界上,正如结构大小(24字节)所预期的那样.

相比之下(与本答案的早期版本相反),使用Clang(Apple LLVM version 8.1.0 (clang-802.0.42))进行编译会产生结果:

sizeof(struct a) = 24
a1 = 0x0000000102ACE020
a2 = 0x0000000102ACE038
a3 = 0x0000000102ACE050
a4[0] = 0x0000000102ACE070
a4[1] = 0x0000000102ACE088
a4[2] = 0x0000000102ACE0A0
a4[3] = 0x0000000102ACE0B8
Run Code Online (Sandbox Code Playgroud)

请注意,单个结构现在以24字节边界布局(或者至少相隔24个字节而不是GCC).

我没有解释为什么GCC增加空间,但编译器完全可以自由地这样做.两个编译器都是正确的 - 结果完全不同.