1

在编程时(例如,在 C 中),很多变量都保存在堆栈中。栈是一种先进先出的数据结构,我们只能弹出栈顶的值。

假设我有 100 个变量存储在堆栈中,我想获取其中一个的值,它不在堆栈的顶部。我如何得到它?操作系统是否会弹出堆栈中所有较新的变量,直到获得想要的变量,然后将它们全部推回内部?或者操作系统是否可以通过不同的方式处理堆栈内的变量?

谢谢

4

2 回答 2

2

I. 操作系统不会直接对您的变量做任何事情。

二、不要将堆栈视为物理堆栈(原因过于简单:它不是一个)。堆栈的元素可以直接访问,编译器会生成这样做的代码。谷歌“堆栈指针相对寻址”。

于 2013-04-10T22:07:01.960 回答
2

在 C 等语言中使用的堆栈不是典型的 LIFO。它被称为堆栈,因为它的使用方式类似于LIFO:当调用一个过程时,一个新的帧被压入堆栈。框架通常包含局部变量和簿记信息,例如返回的位置。类似地,当一个过程返回时,它的帧从堆栈中弹出。

这没有什么神奇之处。编译器(不是操作系统)分配一个寄存器用作堆栈指针——我们称之为SP。按照约定,SP指向下一个空闲堆栈字的内存位置:

+----------------+ (high address)
|   argument 0   |
+----------------+
|   argument 1   |
+----------------+
| return address |
+----------------+
|    local 0     |
+----------------+
|    local 1     |
+----------------+                  +----+    
|    free slot   |  <-------------- | SP |
+----------------+ (low address)    +----+

要将值压入堆栈,我们执行以下操作(在伪汇编中):

STORE [SP], 42 ; store the value 42 at the address where SP points
SUB SP, 1      ; move down (the stack grows down!) to the next stack location

其中符号[SP]被读作“指向的存储单元的内容SP”。一些体系结构,尤其是 x86,提供了push同时执行存储和减法的指令。要弹出(并丢弃)堆栈上的n 个顶部值,我们只需将n添加到SP*.

现在,假设我们要访问local 0上面的字段。如果我们的 CPU 有一个base+offset寻址模式就很容易了!如上图所示,假设SP指向空闲插槽。

 LOAD R0, [SP+2] ; load "local 0" into register R0

注意我们不需要先从堆栈中弹出local 0,因为我们可以使用它与堆栈指针的偏移量来引用任何字段。

根据编译器和机器架构,可能有另一个寄存器指向本地变量和参数(或附近)之间的区域。这个寄存器,通常称为帧指针,在堆栈指针移动时保持固定。

我想强调一个事实,通常情况下,操作系统根本不参与堆栈操作。内核分配初始堆栈,并可能监视其增长,但将值的推送和弹出留给用户程序。

*为简单起见,我假设机器字长为 1 个字节,这就是我们从 SP 中减去 1 的原因。在 32 位机器上,将一个字压入堆栈意味着减去(至少)四个字节。

于 2013-04-10T22:23:07.760 回答