2

我只是想更好地了解地址空间中的堆栈是什么(即您有代码/文本、堆、数据和堆栈)

基本上我的理解是堆栈包含局部变量,但是数据包含的内容和堆栈包含的内容有什么区别?不是数据变量吗?

如果程序对函数 a() 进行递归调用,这是否意味着对于每个递归级别都有一个新堆栈?

4

3 回答 3

5

堆栈通常仅在使用和管理方式上与数据不同。虽然非局部变量本身通常具有已知的特定内存位置,但堆栈上的东西是相对于寄存器(堆栈指针或基指针等)找到的。

堆栈通常包含用于管理堆栈本身的局部变量、传递的参数和控制信息。

而且,如果你进行递归调用,你不会得到一个新的堆栈,只是一个新的堆栈帧。帧是与当前堆栈深度相关的堆栈块(无论是通过递归还是只是常规函数调用)。这就是使递归成为可能的原因,即给定深度的变量独立于其他深度的变量。

请记住,这当然完全取决于架构。我上面的描述是一种常见情况,但有些架构的堆栈完成方式不同,例如 SPARC、System z 和 RCA1802。

可以在此处(框架如何工作)和此处(奇怪的堆栈)找到更多详细信息。

于 2011-05-19T00:40:54.710 回答
1

首先,一个小的澄清。堆栈不一定在 DRAM 中。它们只是一种可以在任何内存中形成的结构:DRAM、缓存、磁盘。

要了解堆栈,您应该首先了解什么是堆栈。它就像一堆托盘,使其成为堆栈的属性是:

  • 您只能访问堆栈的顶部元素
  • 它是后进先出,即,当您从堆栈中获取数据时,您会得到最后存储在堆栈中的数据。

将某些内容存储在堆栈中的行为称为 PUSH,而将其删除称为 POP。假设我对空堆栈执行以下操作:

推一个
按 B
推C

然后堆栈将包含

C - 顶部
乙
一个

现在如果我执行一个 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 
}

我希望以上内容有所帮助。

于 2011-05-19T03:06:52.513 回答
0

以下程序应该可以帮助您了解正在发生的事情。您将看到文本、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 %p\n",x,&pattern);
  printf("deadbeef %d is at %p\n",x,otherpattern);

  if (--x == 0)
  {
    int *off;

    for(off = &pattern;numfeed<TESTS;off++)
    {
      if (*off == 0xfeedface)
        printf("Found feedface #%d at %p\n", ++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 %p\n", 1+TESTS-(++numdead), off);
  }

  printf("numfeed is at %p\n",&numfeed);
  printf("recurse is at %p\n",&recurse);
}
于 2011-05-19T00:58:42.433 回答