我只是想更好地了解地址空间中的堆栈是什么(即你有代码/文本、堆、数据和堆栈)
基本上我的理解是堆栈包含局部变量,但是数据包含的内容和堆栈包含的内容有什么区别? 数据变量不也是吗?
如果一个程序对函数a()有一个递归调用,这是否意味着对于每个递归级别都有一个新的堆栈?
堆栈通常与数据的不同之处仅在于其使用和管理方式。虽然非局部变量本身通常具有已知的特定内存位置,但堆栈上的内容是相对于寄存器(堆栈指针或基指针或类似的东西)找到的。
堆栈通常包含局部变量、传递的参数和用于管理堆栈本身的控制信息。
而且,如果您进行递归调用,则不会获得新的堆栈,只会获得新的堆栈帧。帧是与当前堆栈深度相关的堆栈块(无论是通过递归还是只是常规函数调用)。这就是使递归成为可能的原因,即给定深度的变量独立于其他深度的变量。
请记住,这当然完全取决于体系结构。我上面的描述是一种常见情况,但有些架构的堆栈方式不同,例如SPARC,System z和RCA1802。
更多细节可以在这里(框架如何工作)和这里(奇怪的堆栈)找到。
首先,一个小的澄清。堆栈不一定在 DRAM 中。它们只是可以在任何内存中形成的结构:DRAM,缓存,磁盘。
要了解堆栈,您应该首先了解什么是堆栈。它就像一堆托盘,使其成为堆栈的属性是:
- 您只能访问堆栈的顶部元素
- 它是后进先出,即当您从堆栈中获取数据时,您会获得堆栈上最后存储的数据。
在堆栈中存储某些内容的行为称为 PUSH,删除它的行为称为 POP。 假设我对空堆栈执行以下操作:
推 A推 B推 C
然后堆栈将包含
C - 顶部B一个
现在,如果我执行一个 POP(请注意这里没有操作数),它将返回 C,堆栈将包含
B -- 堆栈顶部一个
所以处理器中的堆栈只是上述算法的硬件实现。
寄存器包含称为堆栈点的堆栈顶部的地址ISA(指令集架构)提供了 PUSH 和 POP 指令来访问堆栈变量,如我上面所示。
这是一个非常有用的结构。堆栈用于存储局部变量,基本上是要在函数调用结束时删除的临时数据。它特别有助于函数调用。调用函数时,新调用函数的局部变量的变量将推送到堆栈上。
foo(){
int a;
int b; // both registers containing a and b are PUSHed here on the stack
c = bar(); // pop the stack to get value of c
print c
}
bar(){
int z; // local variables pushed on top of the stack
z = ...
return z; // pop all local variables of bar(), then push z on the stack
}
我希望以上内容有所帮助。
以下程序应该可以帮助您了解正在发生的事情。 您将看到文本、bss、堆和堆栈的指针示例。 文本通常是可执行代码,bss是静态/全局变量,堆是动态分配的内存,堆栈包含局部变量。
#include <stdlib.h>
#include <stdio.h>
#define TESTS 10
int numfeed = 0;
int numdead = 0;
recurse(int x)
{
u_int pattern=0xfeedface;
u_int *otherpattern = malloc(4);
*otherpattern = 0xdeadbeef;
printf("Feedface %d is at %pn",x,&pattern);
printf("deadbeef %d is at %pn",x,otherpattern);
if (--x == 0)
{
int *off;
for(off = &pattern;numfeed<TESTS;off++)
{
if (*off == 0xfeedface)
printf("Found feedface #%d at %pn", ++numfeed, off);
if (*off == 0xdeadbeef)
printf("Found deadbeef #%d at %p -- WHAT?!?!!?!?n", ++numdead, off);
}
}
else
{
recurse(x);
}
// Not freeing otherpattern intentionally.
}
main()
{
u_int *otherpattern = malloc(4);
*otherpattern = 0xdeadbeef;
int *off;
recurse(TESTS);
for(off = otherpattern+1;numdead<TESTS;off++)
{
if (*off == 0xfeedface)
printf("Found feedface #%d at %p -- WHAT?!?!!!?!?n", ++numfeed, off);
if (*off == 0xdeadbeef)
printf("Found deadbeef #%d at %pn", 1+TESTS-(++numdead), off);
}
printf("numfeed is at %pn",&numfeed);
printf("recurse is at %pn",&recurse);
}