堆栈 - 为什么PUSH和POP?

时间:2009-01-07 13:35:39

标签: stack

我想知道为什么我们使用术语“推”和“弹出”来添加/删除堆栈中的项目?是否有一些物理比喻导致这些术语变得普遍?

我唯一的建议是spring-loaded magazine for a handgun,其中轮次被“推入”并且可以“弹出”,但这似乎不太可能。

第二个堆栈问题:为什么大多数CPU实现调用堆栈在内存中增长向下,而不是向上?

11 个答案:

答案 0 :(得分:22)

关于你的第二个问题,维基百科有一篇关于控制堆栈的CS哲学的文章:

http://en.wikipedia.org/wiki/LIFO

第一个,也是维基百科:

  

一个经常使用的比喻就是这个想法   在春天的一堆盘子   装自助餐厅堆栈。在这样的   堆叠,只有顶板可见   所有其他人都可以访问   板块保持隐藏。作为新板块   添加,每个新的板块成为   堆栈顶部,隐藏每个板块   在下面,推着一堆盘子   下。随着顶板被移除   堆栈,他们可以使用,   板块弹回,第二个   板块成为堆栈的顶部。   两个重要原则是   这个比喻说明:最后   先出原则是一个;该   第二是内容   堆栈是隐藏的。只有顶板   是可见的,所以看看是什么   第三板,第一板和第二板   必须移除板块。这个   也可以写成FILO-First In   Last Out,即插入的记录   首先会被淘汰出局。

答案 1 :(得分:13)

我相信弹簧堆叠的板块是正确的,作为术语PUSH和POP的来源。

特别是麻省理工学院的东校区公共自助餐厅在1957 - 1967年的时间框架内有春天堆积的板块。术语PUSH和POP将由Tech Model Railroad Club使用。我认为这是起源。

Tech Model Railroad Club肯定影响了数字设备公司(DEC)PDP-6的设计。 PDP-6是第一批在硬件中具有面向堆栈指令的机器之一。说明书是PUSH,POP,PUSHJ,POPJ。

http://ed-thelen.org/comp-hist/pdp-6.html#Special%20Features

答案 2 :(得分:13)

对于第二个问题:小型系统上的汇编程序员倾向于编写从内存中的低地址开始的代码,并随着更多代码的增加而扩展到更高的地址。

因此,使堆栈向下增长允许您在物理内存的顶部启动堆栈,并允许两个内存区域朝向彼此增长。这简化了这种琐碎环境中的内存管理。

即使在具有隔离ROM / RAM的系统中,固定数据分配也最容易从下到上构建,因此取代了上述解释的代码部分。

虽然这种琐碎的存储器方案已经非常罕见,但硬件实践仍在继续。

答案 3 :(得分:6)

把它想象成一台pez饮水机。你可以推出一个新的。然后把它从顶部弹出。

当我认为推和弹时,这总是我的想法。 (虽然可能不是很历史)

你问自己PEZ究竟是什么?请参阅评论。

答案 4 :(得分:5)

头韵总是很有吸引力(看我在那里做了什么?),这些话很简短,有说服力,有启发性。旧的BASIC命令peek和poke也是如此,它们具有并行k的额外优势。

一个常见的物理比喻是一个自助餐盘式分配器,其中一个弹簧加载的一叠板使得你可以从顶部取下一个盘子,但是下一个盘子上升到相同的位置。

答案 5 :(得分:5)

重新提出你的“第二个琐碎的问题”:我在定义“向上”和“向下”的含义时看到了相当大的不一致!从早期开始,一些制造商和作者在页面顶部绘制了具有低地址的存储器图(可能模仿了读取页面的顺序),而其他制造商和作者则将高地址放在页面顶部(可能是模仿图纸坐标)或建筑物中的地板。)

当然,堆栈的概念(以及可寻址存储器的概念)与这些视觉隐喻无关。可以实现在任一方向上“增长”的堆栈。事实上,我经常看到下面的技巧(在裸机级实现中)用于共享两个堆栈之间的内存区域:

+---+---+--------   -------+--+--+--+
|   |   |   ->   ...   <-  |  |  |  |
+---+---+--------   -------+--+--+--+
^                                   ^
Stack 1      both stacks      Stack 2
base        "grow" toward        base
              the middle

所以我的答案是,概念上的堆栈从不增长“向下”或“向上”,而只是从他们的基础增长。单个堆栈可以在任一方向实现(或者在既不方向,如果它使用带有垃圾收集的链接表示,在这种情况下元素可能在任何地方在节点空间中。)

答案 6 :(得分:2)

this page上的答案几乎可以回答堆栈方向问题。如果我不得不总结一下,我会说它是向下完成的,以便与古老的计算机保持一致。

答案 7 :(得分:0)

我认为最初的故事是因为一些开发人员看到了板堆(就像你经常在自助餐厅看到的那样)。你把一个新的盘子推到了堆叠的顶部,你也从顶部弹了一个。

答案 8 :(得分:0)

对于在内存中向下增长的堆栈,请记住在处理分层数据结构(树)时,大多数程序员都乐于在页面顶部(或主干)的页面上绘制一个... < / p>

答案 9 :(得分:0)

我知道这个帖子真的很旧,但我想到了第二个问题:

在我看来,即使内存地址减少,堆栈也会增长。如果你要在一张纸上写下一大堆数字,你会从左上角开始,然后是0.然后你会增加从左到右,从上到下的数字。所以说堆栈是这样的:

000 001 002 003 004     000 001 002 003 004     000 001 002 003 004
005 006 007 008 009     005 006 007 008 009     005 006 007 008 009
010 011 012 013 014     010 011 012 013 014     010 011 012 013 014
015 016 017 018 019     015 016 017 018 019     015 016 017 018 019
020 021 022 023 024     020 021 022 023 024     020 021 022 023 024
025 026 027 028 029     025 026 027 028 029     025 026 027 028 029

其中粗体数字表示堆栈内存,而unbold数字表示堆栈未使用的内存地址。每个相同数字的块代表调用堆栈增长的程序阶段。

即使内存地址向下移动,堆栈也在向上增长。

同样,使用弹簧加载的板堆,
如果你从堆栈的顶部取下一个盘子,你会称第一个盘子(最小的数字)对吗?甚至认为它是最高的。程序员甚至可能称之为第零盘。

答案 10 :(得分:0)

关于为什么堆栈会长大的问题,我认为它用于节省内存。

如果你从堆栈内存的顶部(最高值地址)开始并且工作到零,我认为更容易检查你是否已经到达地址$0x00000000而不是分配一个变量来给你最大值堆栈的高度并检查您是否已到达该地址。

我认为这样可以更容易地检查您是否到达可寻址空间的末尾,因为无论有多少可用内存,堆栈的限制始终为$0x00000000