根据 x86 架构中使用的调用约定,参数在函数调用时通过堆栈传递。推进参数的顺序据说是从从右到左。下面的例子符合它。
#include <stdio.h>
void test(int a, int b, int c) {
printf("%p\n%p\n%p\n", &a, &b, &c);
}
int main(void) {
int a = 1;
int b = 2;
int c = 3;
test(a, b, c);
return 0;
}
结果是:
0xffbc4bf0
0xffbc4bf4
0xffbc4bf8
我能理解,但是这里的参数似乎既不是降序也不是升序:
#include <stdio.h>
void test(int a, char b, int c) {
printf("%p\n%p\n%p\n", &a, &b, &c);
}
int main(void) {
int a = 1;
char b = 2;
int c = 3;
test(a, b, c);
return 0;
}
结果是:
0xffd6fda0
0xffd6fd88
0xffd6fdac
b
的地址不在a
和c
之间。为什么会这样?
更新
编译器: gcc 4.8.4
操作系统:Ubuntu 14.04 x86-64
编译命令: gcc -m32 -o test test.c
最佳答案
您的问题的基础是将参数传递给程序。考虑您的函数,它打印每个参数的地址。
void test(int a, int b, int c)
{
print("a=%p, b=%p, c=%p\n", &a, &b, &c);
}
当参数被传递给函数时,它们按顺序被压入堆栈。
所以当函数test()
执行时,a
、b
和c
的值会从栈中使用(并在返回时删除)。
因为编译器正在优化您的代码,所以这些变得乱序了。它首先打包较小的 char
- 可能是为了防止有更多的字符可以打包到同一个 word
中。许多架构在访问非字对齐边界上的项目时都会有速度损失。字长取决于架构。所以编译器重新安排你的参数以获得更好的性能并不是没有道理的。在这里,编译器似乎正在缩小项目以获得更好的尺寸性能(或类似性能)。
考虑这两组结果,GCC 7.3.0
没有优化:
$ ./stack_a.exe
0xffffcbf0
0xffffcbf8
0xffffcc00
$ ./stack_b.exe
0xffffcbf0
0xffffcbf8 <-- in order, used 8 bytes
0xffffcc00
并且经过优化 (-O7):
$ ./stack_a.exe
0xffffcc14
0xffffcc18
0xffffcc1c
$ ./stack_b.exe
0xffffcc18
0xffffcc17 <-- out of order, used 1 byte
0xffffcc1c
有趣的是,它在非优化运行时为每个项目保留 8 个字节(64 位正常),但在优化时将这些更改为 4 个字节。
关于C:如果参数从右向左压入,为什么会出现下面的情况? (64位操作系统,32位程序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52416651/