C专家编程 第6章 运行的诗章:运行时数据结构 6.4 C语言运行时系统在a.out里都干了些什么

    运行时结构有好几种:堆栈、活动记录(activation record)、数据、堆等

    堆栈段
    堆栈段包含了一种单一的数据结构---堆栈。堆栈是一个经典的计算机科学对象。它是一块动态内存区域,实现了一种“先进后出”的结构,有点类似于自助餐厅里叠在一起的盘子。堆栈的经典定义是它可以放置任意数量的盘子,但唯一有效的操作就是从顶部放或取一个盘子。也就是说,值既可以压到堆栈中,也可以通过出栈取得值。入栈操作使堆栈变长,出栈操作从堆栈中取出一个值。

    编译器设计者采用了一种稍显灵活的方法。我们可以从顶部增加或拿掉盘子,也可以修改位于堆栈中部的盘子的值。函数可以通过参数或全局指针访问它所调用的函数的局部变量。运行时系统维护一个指针(常位于寄存器中),通常称为sp,用于提示堆栈当前的顶部位置。
    堆栈段有3个主要的用途,其中两个跟函数有关,另一个跟表达式有关。
    *堆栈为函数内部声明声明的局部变量提供存储空间。按照C语言的术语,这些变量被称为自动变量。
    *进行函数调用时,堆栈存储与此有关的一些维护性信息,这些信息被称为堆栈结构(stack frame),另外一个更常用的名字是过程活动记录(precedure activation record)。现在只要知道它包括函数调用地址(即所调用的函数结束后跳回的地方),任何不适合装入寄存器的参数以及一些寄存器值的保存即可。
    *堆栈也可以被用作暂时存储区。有时候程序需要一些临时存储。通过alloca()函数分配的内存就位于堆栈中。如果想让内存在函数调用结束之后仍然有效,就不要使用alloca()来分配(它将被下一个函数调用所覆盖)。

    除了递归调用之外,堆栈并非必需的。因为在编译时刻可以知道局部变量、参数和返回地址所需空间的固定大小,并可以将它们分配于BSS段。允许递归调用意味着必须找到一种方法,在同一时刻允许局部变量的多个实例存在,但只有最近被创建的那个才能被访问,这很像堆栈的经典定义。 

    /*堆栈的大致位置*/ 
    #include <stdio.h>
    int glob_var = 1;
    int glob_unit_var;
    static int local_var = 2;
    static int local_unit_var;
    int main() {
        int i;
        int j[5];
        printf("glob_var = %p\nglob_unit_var = %p\nlocal_var = %p\nlocal_unit_var = %p\n\n", &glob_var, &glob_unit_var, &local_var, &local_unit_var);
        printf("The stack top is near %p\n\n", &i);
        for (int index = 0; index < 5; ++index) {
            printf("&j[%d] = %p\n", index, &j[index]);
        }
    
        return 0;
    }

输出:

堆栈向上增长的,也就是朝着低地址方向生长。相信你肯定还能看出其他的结论。
    要发现数据段和文本段,以及位于数据段内的堆,方法是声明位于这些段的变量,并打印它们的地址。通过调用函数和声明一些大型局部数组使堆栈增长。

    在不同的计算机架构中和不同的操作系统中,堆栈的位置可能各不相同。事实上在绝大多数处理器中,堆栈是向下增长的,也就是朝着低地址方向生长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值