我一直在研究我的计算机在引擎盖下是如何工作的。我感兴趣的是看到函数内部堆栈上发生的事情。为此,我编写了以下玩具程序:
#include <stdio.h>
void __cdecl Test1(char a, unsigned long long b, char c)
{
char c1;
unsigned long long b1;
char a1;
c1 = 'b';
b1 = 4;
a1 = 'r';
printf("%d %d - %d - %d %d Total: %d\n",
(long)&b1 - (long)&a1, (long)&c1 - (long)&b1,
(long)&a - (long)&c1,
(long)&b - (long)&a, (long)&c - (long)&b,
(long)&c - (long)&a1
);
};
struct TestStruct
{
char a;
unsigned long long b;
char c;
};
void __cdecl Test2(char a, unsigned long long b, char c)
{
TestStruct locals;
locals.a = 'b';
locals.b = 4;
locals.c = 'r';
printf("%d %d - %d - %d %d Total: %d\n",
(long)&locals.b - (long)&locals.a, (long)&locals.c - (long)&locals.b,
(long)&a - (long)&locals.c,
(long)&b - (long)&a, (long)&c - (long)&b,
(long)&c - (long)&locals.a
);
};
int main()
{
Test1('f', 0, 'o');
Test2('f', 0, 'o');
return 0;
}
这会吐出以下内容:
9 19 - 13 - 4 8 总计:53
8 8 - 24 - 4 8 总计:52
函数 args 表现良好,但由于指定了调用约定,我希望如此。但是局部变量有点不稳定。我的问题是,为什么这些不一样?第二次调用似乎产生了一个更紧凑和更好对齐的堆栈。
查看 ASM 是没有启发性的(至少对我而言),因为那里的变量地址仍然是别名。所以我想这确实是一个关于汇编程序本身将堆栈分配给局部变量的问题。
我知道任何特定的答案都可能是特定于平台的。我对一般解释更感兴趣,除非这个怪癖真的是特定于平台的。不过郑重声明,我是在 64 位 Intel 机器上使用 VS2010 进行编译。
最佳答案
POD 结构的内存布局几乎由您平台上的语言规则 + 类型对齐/大小要求指定和保证。
实现可以自由处理局部变量和函数参数。很可能它只是将其中一些放入堆栈,因为您使用一元 & 运算符获取它们的地址。
当不使用局部变量时,编译器可能会优化它的初始化。当非常密集地使用局部简单变量时,编译器可能会为其使用寄存器。当局部变量只使用一次时,编译器可以直接使用它的值来代替用法。
如果你想更好地指定/保证功能参数布局,那么你必须使用外部“C”链接。
关于c++ - 基本数据对齐问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4534766/