我一直在玩,看看我的电脑是如何工作的。我感兴趣的是看到函数内部堆栈上发生了什么。为此,我写了以下玩具程序:
#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进行编译。
答案 0 :(得分:1)
POD结构的内存布局几乎是由平台上的语言规则+类型对齐/大小要求指定和保证的。
实现可以随心所欲地使用局部变量和函数参数。它很可能只是因为你使用一元&amp;而把它们中的一些放入堆栈中。运营商拿走他们的地址。
当未使用局部变量时,编译器可以优化其初始化。当非常密集地使用本地简单变量时,编译器可以使用寄存器。当局部变量仅使用一次时,编译器可以直接使用其值代替使用。
如果希望更好地指定/保证功能参数布局,则必须使用extern“C”链接。
答案 1 :(得分:0)
在Test1中,您定义了一堆局部变量。编译器不会被强制将它们打包在一起,或者按照您声明的顺序打包它们。
在Test2中,您使用http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86
定义结构和编译器填充数据