我在c中有这段代码:
int q = 10;
int s = 5;
int a[3];
printf("Address of a: %d\n", (int)a);
printf("Address of a[1]: %d\n", (int)&a[1]);
printf("Address of a[2]: %d\n", (int)&a[2]);
printf("Address of q: %d\n", (int)&q);
printf("Address of s: %d\n", (int)&s);
Run Code Online (Sandbox Code Playgroud)
输出是:
Address of a: 2293584
Address of a[1]: 2293588
Address of a[2]: 2293592
Address of q: 2293612
Address of s: 2293608
Run Code Online (Sandbox Code Playgroud)
所以,我看到,从那里a开始a[2],内存地址每个增加4个字节.但是,从q到s,内存地址减少了4个字节.
我想知道两件事:
a[2]和q内存地址之间发生了什么?为什么那里存在很大的记忆差异?(20个字节).注意:这不是作业问题.我很好奇堆栈是如何工作的.谢谢你的帮助.
Gan*_*ian 70
堆栈(成长或增长)的行为取决于应用程序二进制接口(ABI)以及如何组织调用堆栈(也称为激活记录).
在其整个生命周期中,程序必然会与其他程序(如OS)进行通信.ABI确定程序如何与另一个程序通信.
不同体系结构的堆栈可以以任何一种方式增长,但对于体系结构,它将是一致的.请检查此维基链接.但是,堆栈的增长是由该架构的ABI决定的.
例如,如果您使用MIPS ABI,则调用堆栈定义如下.
让我们考虑函数'fn1'调用'fn2'.现在'fn2'看到的堆栈帧如下:
direction of | |
growth of +---------------------------------+
stack | Parameters passed by fn1(caller)|
from higher addr.| |
to lower addr. | Direction of growth is opposite |
| | to direction of stack growth |
| +---------------------------------+ <-- SP on entry to fn2
| | Return address from fn2(callee) |
V +---------------------------------+
| Callee saved registers being |
| used in the callee function |
+---------------------------------+
| Local variables of fn2 |
|(Direction of growth of frame is |
| same as direction of growth of |
| stack) |
+---------------------------------+
| Arguments to functions called |
| by fn2 |
+---------------------------------+ <- Current SP after stack
frame is allocated
Run Code Online (Sandbox Code Playgroud)
现在你可以看到堆栈向下增长.因此,如果变量被分配给函数的本地帧,则变量的地址实际上向下增长.编译器可以决定内存分配的变量顺序.(在你的情况下,它可以是'q'或's',它是第一次分配的堆栈内存.但是,通常编译器会根据变量声明的顺序堆栈内存分配).
但是在数组的情况下,分配只有单个指针,而需要分配的内存实际上是由单个指针指向的.内存需要与数组连续.因此,尽管堆栈向下增长,但对于数组,堆栈会增长.
Cra*_*rks 44
这实际上是两个问题.一个是关于当一个函数调用另一个函数时(当分配新帧时)堆栈增长的方式,另一个是关于如何在特定函数的框架中布置变量.
C标准都没有规定,但答案有点不同:
f帧指针是否大于或小于g帧的指针? 这可以采用任何一种方式 - 它取决于特定的编译器和体系结构(查找"调用约定"),但它在给定平台内始终保持一致(有一些奇怪的例外,请参阅注释).向下是更常见的; 在x86,PowerPC,MIPS,SPARC,EE和Cell SPU中就是这种情况.R S*_*hko 13
堆栈增长的方向是体系结构特定的.也就是说,我的理解是只有极少数硬件架构具有成长的堆栈.
堆栈增长的方向与单个对象的布局无关.因此,当堆栈可能长大时,数组将不会(即&array [n]将始终为<&array [n + 1]);
标准中根本没有规定如何在堆栈上组织事物。事实上,您可以构建一个完全不将数组元素存储在堆栈上的连续元素处的一致编译器,只要它有能力正确执行数组元素算术(以便它知道,例如,1是距离 a[0] 1K,可以对此进行调整)。
您可能得到不同结果的原因是,虽然堆栈可能会向下增长以向其中添加“对象”,但数组是单个“对象”,并且它可能具有按相反顺序升序的数组元素。但依赖这种行为并不安全,因为方向可能会改变,变量可能会因多种原因而交换,包括但不限于:
请参阅此处我关于堆栈方向的精彩论文:-)
回答您的具体问题: