我一直试图了解编译器如何在64 / 32bit机器上对齐堆栈变量。
看看下面的代码:
void Test()
{
int x = 1;
int y = 2;
int z = 3;
}
我发现:
&x > &y > &z
是真的。&x - &y
和&y - &z
对他们两个都是3。这意味着每个变量被8个额外字节填充。对于64位机器上的32位应用程序,我期望变量不需要任何对齐,即差异应该是1而不是3。
有人可以解释一下吗? 谢谢!
环境详情:
64位Windows 7,Visual Studio 2010,应用程序配置:x86
答案 0 :(得分:2)
正如@HansPassant和其他人所指出的,堆栈上的变量对齐是一个实现细节。一旦启用了优化,你甚至不能确定它们中的任何一个将在堆栈中(除非你获取它的地址) - 每个都可以优化到寄存器。
只是为了说明:测试程序
#include <stdio.h>
#include <windows.h>
int main() {
int x = 1, y = 2, z = 3;
printf("%d,%d,%d,%d\n",&y-&x,&z-&y,(BYTE*)&y-(BYTE*)&x,(BYTE*)&z-(BYTE*)&y);
}
在这里打印(win7 x64,vs2012 x86编译器):
>cl /nologo t.c >nul && t.exe
2,-1,8,-4
>cl /Ox /nologo t.c >nul && t.exe
-2,1,-8,4
>cl /RTC1 /Ox /nologo t.c >nul && t.exe
-3,-3,-12,-12
在最后一种情况下,/ RTC在变量to detect out-of-bounds access之间插入间隙。
关于默认路由,编译器遵守英特尔的建议,因为x86在访问未对齐数据时会受到惩罚。这里,具体来说,它是 Intel® 64 and IA-32 Architectures Optimization Reference Manual,第3.6.7节“堆栈对齐”:
当a时,会发生对堆栈的未对齐访问的性能损失 内存引用拆分缓存行。这意味着八分之一 空间连续的未对齐四字访问总是受到惩罚, 类似地,对于4个连续的非对齐双四字中的一个 访问等。
任何时候对齐堆栈都可能是有益的 超出系统默认堆栈对齐的数据对象。 例如,在32 / 64bit Linux和64bit Windows上,默认堆栈 对齐是16个字节,而32位Windows是4个字节。
汇编/编译器编码规则55.(H影响,M概括性) 确保 堆栈以最大的多字节粒度数据类型对齐 边界匹配寄存器宽度。
对于较长的类型(浮点),even higher alignments are recommended for the same purpose。