堆栈 - 为啥是 PUSH 和 POP?
Posted
技术标签:
【中文标题】堆栈 - 为啥是 PUSH 和 POP?【英文标题】:Stacks - why PUSH and POP?堆栈 - 为什么是 PUSH 和 POP? 【发布时间】:2010-09-30 00:53:34 【问题描述】:我想知道为什么我们使用术语“推”和“弹出”来添加/删除堆栈中的项目?是否有一些物理隐喻导致这些术语很常见?
我唯一的建议是类似spring-loaded magazine for a handgun,其中子弹被“推入”并可以“弹出”出来,但这似乎不太可能。
第二个堆栈琐事问题:为什么大多数 CPU 将调用堆栈实现为在内存中向下而不是向上增长?
【问题讨论】:
实际上,6502 和 6800 是两个著名的知名 CPU,它们使用“拉”来表示“推”的反义词。 在一些旧的、不起眼的 CPU 上,POP 不是“拉操作数”的助记符吗? 艾伦·图灵在 1946 年使用的原始术语是 bury 和 unbury - en.wikipedia.org/wiki/Stack_(abstract_data_type)。 【参考方案1】:关于你的第二个问题,***有一篇关于控制堆栈的 CS 哲学的文章:
http://en.wikipedia.org/wiki/LIFO
首先,也在***上:
一个常用的比喻是想法 弹簧中的一堆板 加载自助餐厅堆栈。在这样一个 堆栈,只有顶板可见 并且用户可以访问,所有其他 盘子仍然隐藏。作为新板 被添加,每个新盘子成为 堆栈的顶部,隐藏每个盘子 下面,推着一堆盘子 下。当顶板从 堆栈,它们可以被使用, 盘子弹回来,第二个 盘子成为堆栈的顶部。 两个重要原则是 用这个比喻来说明:最后 先进先出原则是一个;这 其次是内容 堆栈被隐藏。只有顶板 是可见的,所以看看上面有什么 第三盘,第一盘和第二盘 盘子必须被移除。这 也可以写成 FILO-First In Last Out,即插入的记录 首先会弹出来。
【讨论】:
我见过的枪支和步枪弹匣比我见过的自助餐厅多得多。 相同。但我觉得更容易想象,因为我从来没有拿过枪。 :P 我喜欢自助餐厅的盘子堆,但是您提供的***链接并不能很好地回答我的第二个问题。 我们在我大学的食堂吃过它们。有时盘子堆得太多,再也推不动了。结果,不仅可以看到顶板... [CONTINUE] ...这些顶板的平衡变得很差,没有任何东西将它们紧紧地固定在适当的位置,这使得它们非常不稳定。有人可以很容易地将它们撞倒。继续类比...堆栈溢出。【参考方案2】:我相信弹簧加载的板叠是正确的,作为术语 PUSH 和 POP 的来源。
特别是,麻省理工学院东校区公共食堂在 1957 年至 1967 年的时间范围内装有弹簧加载的盘子。 Tech Model Railroad Club 会使用 PUSH 和 POP 这两个术语。我想这就是起源。
Tech Model Railroad Club 无疑影响了 Digital Equipment Corporation (DEC) PDP-6 的设计。 PDP-6 是最早在硬件中具有面向堆栈指令的机器之一。指令为 PUSH、POP、PUSHJ、POPJ。
http://ed-thelen.org/comp-hist/pdp-6.html#Special%20Features
【讨论】:
即使这无法证实,它也是一个很好的答案!谢谢。 您可以通过查看 Alan Kotok 的著作来证实这一点。 en.wikipedia.org/wiki/Alan_Kotok 这是有道理的,只是该术语不是在 MIT 发明的。大约在 1951 年,伟大的 Friedrich Bauer 描述了基于图灵概念的“下推”系统(图灵使用了术语“埋葬”和“不埋葬”)。 Bauer 还给了我们软件工程这个词,他仍然和我们在一起。 :-) @T.J.Crowder,假设您是正确的,实际历史肯定应该胜过假定的历史。你有鲍尔使用“下推”的来源吗?德语中的短语是什么? @WalterMitty:还没有找到论文。找到了几个来源,比如this one。【参考方案3】:对于第二个问题:小型系统上的汇编程序员倾向于编写从内存中低地址开始的代码,并随着更多代码的添加而增长到更高地址。
因此,使堆栈向下增长允许您从物理内存的顶部开始堆栈,并允许两个内存区域相互增长。这简化了这种琐碎环境中的内存管理。
即使在具有隔离 ROM/RAM 固定数据分配的系统中,也最容易自下而上构建,从而替换上述说明的代码部分。
虽然这种微不足道的内存方案已经很少见了,但硬件实践仍在继续。
【讨论】:
【参考方案4】:把它想象成一个 pez 分配器。你可以在上面推一个新的。然后将其从顶部弹出。
当我想到 push 和 pop 时,我总是这么想。 (虽然可能不是很有历史意义)
您是否在问自己 PEZ 到底是什么?查看 cmets。
【讨论】:
...呃,pez 分配器是什么? 我也一直将其视为 Pez 分配器。 +1 类比 images.google.com/… Pez 是我最喜欢的糖果之一! 这是一件很糟糕的事情,我在欧洲的任何地方都没有见过 Pez,只有美国。斯蒂芬·金(Stephen King)在他年轻的时候写关于孩子的文章时经常提到佩斯en.wikipedia.org/wiki/PEZ【参考方案5】:关于您的“第二个微不足道的问题”:我发现在定义“向上”和“向下”的含义时存在相当大的不一致!从早期开始,一些制造商和作者在页面顶部绘制低地址的内存图(可能模仿读取页面的顺序),而另一些则将高地址放在页面顶部(可能模仿方格纸坐标或建筑物的楼层)。
当然,堆栈的概念(以及可寻址内存的概念)独立于这些视觉隐喻。可以实现一个在任一方向“增长”的堆栈。事实上,我经常看到以下技巧(在裸机级实现中)用于在两个堆栈之间共享内存区域:
+---+---+-------- -------+--+--+--+
| | | -> ... <- | | | |
+---+---+-------- -------+--+--+--+
^ ^
Stack 1 both stacks Stack 2
base "grow" toward base
the middle
所以我的回答是,从概念上讲,堆栈从不“向下”或“向上”增长,而只是从它们的基部增长。单个堆栈可以实现在任一方向(或任一方向,如果它使用带有垃圾收集的链接表示,在这种情况下,元素可能在任何地方 在节点空间中)。
【讨论】:
谢谢。我特别指的是 CPU 中调用堆栈的硬件实现,内存地址从高到低(= 向下!) 对我来说,栈在概念上总是在增长:最近添加的项目总是被认为是栈的顶部。你不能把东西推到底部,否则它就是一个队列(除了队列没有顶部或底部)。接近顶部时地址是增加还是减少是分开的。【参考方案6】:头韵总是很吸引人(看看我在那儿做了什么?),这些词很短,头韵,暗示。旧的 BASIC 命令 peek 和 poke 也是如此,它们具有并行 k 的额外优势。
一个常见的物理隐喻是自助餐厅的盘子分配器,其中弹簧加载的盘子堆叠使您可以从顶部取出一个盘子,但下一个盘子会升起到相同的位置。
【讨论】:
从技术上讲不是头韵,因为头韵是相同起始辅音声音en.wikipedia.org/wiki/Alliteration的重复 你知道什么!我每天都学到新东西。我找不到一个与元音有相同含义的词,我想知道为什么?【参考方案7】:this page 上的答案几乎可以回答堆栈方向问题。如果非要总结的话,我会说它是向下做的,以保持与古代计算机的一致性。
【讨论】:
有人记得 6502 吗?硬件堆栈位于一个代码页(我认为是第 1 页)中,因此限制为 256 个字节。 我愿意 :) 我的第一个汇编器 - 6502 有 3 个寄存器(A、X、Y),加上堆栈,第一页 (00-FF) 用于索引 w/ Y(大部分)和 X (但几乎没有),第二个(100-1FF)是堆栈。在过去,直接编写代码是内存迭代的标准方式,除非使用零页地址(而且它们很宝贵)【参考方案8】:我认为最初的故事是因为一些开发人员看到了盘子堆(就像你经常在自助餐厅看到的那样)。您将一个新盘子推到堆栈的顶部,并且您也从顶部弹出了一个。
【讨论】:
【参考方案9】:关于在内存中向下增长的堆栈,请记住,在处理分层数据结构(树)时,大多数程序员都乐于在页面顶部绘制一个底部(或树干)的页面......
【讨论】:
【参考方案10】:我知道这个帖子真的很老了,但是我对第二个问题有一个想法:
在我看来,堆栈会增长,尽管内存地址会减少。如果你要在一张纸上写一大堆数字,你会从左上角开始,从 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其中粗体数字表示堆栈内存,非粗体数字表示堆栈未使用的内存地址。每个相同数字的块代表调用堆栈增长的程序的一个阶段。
即使内存地址向下移动,堆栈也在向上增长。
类似地,使用弹簧加载板组, 如果您从堆栈顶部取出一个盘子,您会称其为第一个盘子(最小的数字),对吗?甚至认为它是最高的。程序员甚至可以称它为第零板。
【讨论】:
【参考方案11】:关于栈为什么会变小的问题,我想是用来节省内存的。
如果您从堆栈内存的顶部(最高值地址)开始并工作到零,我认为检查您是否已到达地址 $0x00000000
比分配一个变量给您的最大高度更容易堆栈并检查您是否已到达该地址。
我认为这样可以更轻松地检查您是否已到达可寻址空间的末尾,因为无论有多少可用内存,堆栈的限制始终为$0x00000000
。
【讨论】:
以上是关于堆栈 - 为啥是 PUSH 和 POP?的主要内容,如果未能解决你的问题,请参考以下文章