我有一些关于C语言内存对齐的问题,以及在使用_Alignas说明符强制变量与一定数量的字节对齐后如何分配内存。
此代码在输出中显示每个声明变量的内存地址:
#include <stdio.h>
int main(void)
{
unsigned char dx = 1;
unsigned char ca = 1;
unsigned char cx = 1;
unsigned char dz = 1;
unsigned char cb = 1;
unsigned char _Alignas(double) cz = 1;
char * p_begin = (char *) &cz;
char * p_end = (char * ) &dx + sizeof(dx);
printf("Addresses Value\n");
for (char * p = p_begin; p < p_end; p++)
{
printf("%9p %6X", p, 0xff & *p);
if (p == (char *) & dx) printf(" <- dx\n");
else if (p == (char *) & ca) printf(" <- ca\n");
else if (p == (char *) & cx) printf(" <- cx\n");
else if (p == (char *) & dz) printf(" <- dz\n");
else if (p == (char *) & cb) printf(" <- cb\n");
else if (p == (char *) & cz) printf(" <- cz\n");
else printf("\n");
}
return 0;
}
在我的电脑上,输出如下:
Addresses Value
28ff08 1 <- cz
28ff09 FF
28ff0a 28
28ff0b 0
28ff0c CE
28ff0d 2A
28ff0e 40
28ff0f 1 <- cb
28ff10 1 <- dz
28ff11 1 <- cx
28ff12 1 <- ca
28ff13 1 <- dx
Process returned 0 (0x0) execution time : 0.016 s
Press any key to continue.
在8字节强制cz
变量对齐后,我希望看到的唯一行为是cz
被分配给一个值为8的倍数的地址,我不希望这样做请参阅填充中的cz
。怎么来这个行为?
另外我预计对应于填充的字节数与1字节的数据大小相结合会产生8,而填充占用6个字节的原因是什么?
答案 0 :(得分:0)
您的示例中似乎发生的是编译器按照遇到的顺序为对象分配空间。首先会看到dx
,因此会为堆栈0x28ff13
分配下一个可用空间。然后会看到ca
,并为其分配0x28ff12
。我们看到,随着堆栈的增长,它从更高的地址(它开始的地方)开始到更低的地址。
当编译器到达cz
时,您已请求八字节对齐,编译器跳转到下一个八的倍数(仍在向下方向),即0x28ff08
。< / p>
当然编译器可以查看整个情况(而不是一次查看每个对象)并将cz
放在0x28ff10
并将其他对象放在它周围,使用更少的堆栈空间。如果在启用优化的情况下进行编译,编译器可能会这样做。另一方面,编译器可能要求您的平台将堆栈指针保持对齐八个字节(或更多),因此重新排列这些特定对象无论如何都不会保存任何堆栈空间。
C标准中没有关于此的规则。编译器可以自由选择它的堆栈。