运行时堆栈是否保存在内存的数据段中?

时间:2009-04-29 14:36:00

标签: c++ c memory stack segments

在我对后台正在进行的实验进行实验后,我对堆栈内存组织非常好奇,显然它与我从书本中获得的微小知识相匹配。只是想检查我所理解的是否正确。

我有一个基本程序 - 有2个函数,第一个是foo,另一个是main(入口点)。

void foo(){
    // do something here or dont
}

int main(){

    int i = 0;

    printf("%p %p %p\n",foo, &i, main);

    system("PAUSE");
    return EXIT_SUCCESS;
};

程序的输出如下所示,main的局部变量i完全位于不相关的位置。 integer是一个值类型,但是使用char本地的char *指针再次检查它并获得类似的结果。

00401390 0022FF44 00401396
Press any key to continue . . .

我主要理解代码和变量被分配到不同的内存段(代码段/数据段)。所以基本上说调用堆栈是否会折叠有关函数执行的基本信息(它们的局部变量,参数,返回点)并将它们保存在数据段中是正确的吗?

5 个答案:

答案 0 :(得分:3)

一开始有点需要注意:所有这些答案都受到操作系统和硬件架构的影响。 Windows与UNIX类语言,实时操作系统和旧的小型系统UNIX完全不同。

但@Richie和@Paul所说的基本答案是“是的”。当您的编译器和链接器完成代码时,它会被分解为UNIX中所谓的“文本”和“数据”段。 文本段包含指令和某些静态数据;数据段包含数据。

然后为堆栈和堆空间分配大块数据段。其他块可以分配给静态或外部数据结构等。

所以是的,当程序运行时,程序计数器正忙着从数据的不同段获取指令。现在我们进入一些体系结构依赖关系,但一般来说如果你有分段内存,你的指令就是这样构造的,即从段中获取一个字节尽可能高效。在旧的360体系结构中,它们有基址寄存器,在x86中有一堆头发随着地址空间变为旧8080到现代处理器而增长,但是所有指令都经过了非常仔细的优化,因为正如您可以想象的那样,获取指令及其操作数非常密集使用。

现在我们开始使用虚拟内存和内存管理单元的更现代的架构。现在机器有特定的硬件,让程序将地址空间视为一个大的平坦地址范围;各个段只是放在那个位虚拟地址空间中。 MMU的工作是获取一个虚拟地址并将其转换为物理地址,包括如果该虚拟地址目前根本不在物理内存中该怎么办。同样,MMU硬件经过了大量优化,但这并不意味着没有性能成本相关联。但随着处理器变得越来越快,程序越来越大,它变得越来越不重要了。

答案 1 :(得分:1)

是的,这是完全正确的。代码和数据存在于内存的不同部分,具有不同的权限。堆栈包含参数,返回地址和本地(“自动”)变量,并与数据一起生效。

答案 2 :(得分:0)

想象一下,您的代码存储器是ROM,而您的数据存储器是RAM(一种常见的小型芯片架构)。然后你会看到堆栈必须在数据存储器中。

答案 3 :(得分:0)

您的程序显示未定义的行为,特别是因为:

  • 您未能包含<stdio.h><cstdio>,具体取决于您编写代码的语言
  • printf并且所有变量参数函数都没有能力对其参数进行类型检查。因此,您必须传递正确的类型参数。你真的应该这样做:
  • system()在范围内没有声明。视情况而定包括<stdlib.h><cstdlib>

将您的代码编写为:

   #include <stdio.h>

   int main() {
      /* ... */
      printf("%p %p %p\n", (void *)foo, (void *)&i, (void *)main);
      /* ... */
   }

另请注意:

  • void foo()的定义不是C中的原型,而是C ++中的原型。但是,如果您要写void foo(void),您将获得两种语言的原型。
  • system()依赖于实现 - 您的代码可能无法跨平台运行。

适当的语言(C或C ++)对如何组织内存没有任何限制。它甚至没有堆栈或堆的概念。这些是由他们认为合适的实现定义的。理想情况下,您应该查阅实现提供的文档,以便对其工作有一个全面的了解。

答案 4 :(得分:0)

好吧,我可以代表SPARC:

是。运行程序时,程序将被读取两次(至少在SPARC中)。程序被加载到内存中,然后加载任何数组/堆栈分配。在第二次通过程序时,堆栈被分配到单独的内存中。

我不确定基于CISC的处理器,但我怀疑它没有太大变化。