Recursion DRAM中的堆栈是什么(递归过程中会发生什么)?

Recursion DRAM中的堆栈是什么(递归过程中会发生什么)?,recursion,operating-system,callstack,ram,Recursion,Operating System,Callstack,Ram,我只是想更好地理解地址空间中的堆栈(即代码/文本、堆、数据和堆栈) 基本上我的理解是堆栈包含局部变量,但是数据包含的内容和堆栈包含的内容有什么区别呢?数据变量不是也一样吗 如果程序对函数a()进行递归调用,是否意味着对于每个递归级别都有一个新堆栈?堆栈通常与数据不同,只是在使用和管理方式上不同。虽然非局部变量本身通常有一个已知的特定内存位置,但堆栈上的内容是相对于寄存器(堆栈指针或基指针或类似的内容)找到的 堆栈通常包含用于管理堆栈本身的局部变量、传递的参数和控制信息 而且,如果进行递归调用,则

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

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


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

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

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

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

请记住,这当然取决于体系结构。我上面的描述是一种常见的情况,但是有些体系结构的堆栈执行方式不同,例如SPARC、Systemz和RCA1802


更多的细节可以找到(框架是如何工作的)和(奇怪的堆栈)。

下面的程序应该可以帮助您了解发生了什么。您将看到文本、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);
}
#包括
#包括
#定义测试10
int numfeed=0;
int numdead=0;
递归(int x)
{
u_int模式=0xfeedface;
u_int*otherpattern=malloc(4);
*otherpattern=0xdeadbeef;
printf(“进给面%d位于%p\n”、x和图案处);
printf(“死牛肉%d位于%p\n”,x,其他模式);
如果(--x==0)
{
int*off;

对于(off=&pattern;numfeed首先,有一个小的澄清。堆栈不一定在DRAM中。它们只是一个可以在任何内存中形成的结构:DRAM、缓存、磁盘

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

  • 您只能访问堆栈的顶部元素
  • 它是后进先出(Last-In First Out),也就是说,当您从堆栈中获取数据时,您将获得最后存储在堆栈中的数据
将某些内容存储在堆栈中的行为称为推送,将其移除的行为称为弹出。假设我对空堆栈执行以下操作:

PUSH A PUSH B PUSH C
我希望上述内容能有所帮助。

堆栈并非真正针对DRAM。它们是一种数据结构。它由处理器实现,以简化函数调用和递归。我在下面发布了一些详细信息。据我回忆,这个答案在许多具体细节上都是错误的,尽管在概念上基本正确。特别是返回variables不是典型的(曾经?)使用堆栈完成,而是根据所采用的调用约定,加载带有返回值的特定寄存器。有趣的一点是,没有理由不使用堆栈作为返回值。是否使用堆栈实际上是编译器的一个属性,与堆栈或程序的运行。事实上,摩托罗拉的HC12编译器使用了堆栈。使用寄存器是一种优化,以节省冗余的推送和弹出。如果没有足够的寄存器可用,有时可以使用堆栈。Gcc有时会这样做(很少)这也解释了为什么6812使用堆栈,因为寄存器很少。只是好奇,你还发现我的答案有什么其他错误吗?如果
int z
将z推到堆栈上,并且
return z
也将z推到堆栈上,那么机器代码在返回而不销毁后将无法重置
SP
ng返回值;
RET
指令之前的代码当然不能这样做,但是调用代码需要太多关于被调用子例程的知识(我想除非它将
SP
的原始值存储在寄存器中)。 C - Top B A B -- top of stack A
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 
}