编译器会秘密增加结构的对齐方式吗?



我有一个 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("%lxn", (uintptr_t)&a1);
printf("%lxn", (uintptr_t)&a2);
printf("%lxn", (uintptr_t)&a3);
return 0;
}

输出为:

601030
601050
601070

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

#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) = %zun", 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;
}

产生以下结果:

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

请注意,三个独立结构布置在 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

请注意,单个结构现在布置在 24 字节边界上(或者至少相隔 24 个字节,而不是像 GCC 那样相隔 32 个字节(。

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

最新更新