C:如果将参数从右向左推,为什么会发生以下情况? (64位操作系统,32位程序)

时间:2018-09-20 02:20:59

标签: 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

1 个答案:

答案 0 :(得分:0)

问题的基础是将参数传递给程序。考虑一下您的函数,该函数会打印每个参数的地址

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个字节。