C:如果参数从右向左压入,为什么会出现下面的情况? (64位操作系统,32位程序)

标签 c stack

根据 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 的地址不在ac 之间。为什么会这样?

更新

编译器: 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()执行时,abc的值会从栈中使用(并在返回时删除)。

因为编译器正在优化您的代码,所以这些变得乱序了。它首先打包较小的 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/

相关文章:

c - 互斥锁是否仅在所有相关线程尝试在利用资源之前尝试获取其应获取的锁的情况下才能正常工作?

c - C 中此通用堆栈实现的 "free"函数有什么问题?

c - 查看堆栈中的内容

java - 汉诺塔的堆栈实现和递归 (Java)

operating-system - 内核开发中使用的堆栈大小

java - java.util.Stack 的迭代器中是否有错误?

c - 在 C 中保留一个用于成员资格测试的大列表

c - UndefinedBehaviorSanitizer 因为空指针

c - OpenMPI - 不同进程上的相同排名

c - 函数中引用指针有什么区别