我在 C 中试验堆栈的地址空间,发现了一些让我大吃一惊的东西。以下代码片段调用一个函数,该函数依次打印出内存中以第一个参数的地址开头的整数值。
#include <stdio.h>
#include <stdarg.h>
void func(int arg, int second, ...) {
int i=0;
for (; i < 20; i++) {
int* addr = &arg + i;
printf("* %d\n", *addr);
}
}
int main() {
func(42, 67, 24, 92);
return 0;
}
输出是这样的:
* 42 <
* 1075105048
* -1081967932
* 1073841448
* -16121856
* 1075105060
* 1073828160
* -1081967880
* 134513921
* 42 <
* 67 <
* 24 <
* 92 <
* 134513984
* 0
* -1081967880
* 134513529
* -16121856
* -1081967856
* -1081967816
现在,让我怀疑的是我用 <
标记的行符号。一行中的四个元素等于我传递给函数的参数。但为什么值第一个参数在输出中出现两次?
传递给 C 函数的参数是否有标准化的内存布局,或者 stdarg.h
的实现?极度依赖编译器?
最佳答案
直接查看汇编程序将是解决此问题的更好方法,但我认为两次看到 42 的原因是 st 编译器实现堆栈的方式的人工制品。大多数情况下,堆栈从内存中的高位开始并向下增长。因此,您的函数会将参数存储在 main 函数框架下方的堆栈框架中。然后从第一个参数的地址向上打印。所以你得到第一个参数,然后是堆栈帧的开始,然后是一些主堆栈帧,其中将包括传递给你的函数的参数。这就是为什么你两次看到 42 的原因。 当然,这一论点假设编译器和操作系统以某种方式工作。正如我已经说过的,查看程序集会给你一个更准确的画面。
关于C堆栈内存转储,为什么第一个参数出现两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20587410/