堆栈是自底向上堆积的东西。
因此,当调用函数时,调用堆栈会在堆栈上添加新的项目,并且随着每个函数的结束从堆栈中删除项目,直到堆栈为空,然后程序结束。
如果上述正确,那么为什么人们会提到控件将调用堆栈“上移”?控制肯定会向下移动到调用堆栈,直到到达底部为止。
堆栈是自底向上堆积的东西。
因此,当调用函数时,调用堆栈会在堆栈上添加新的项目,并且随着每个函数的结束从堆栈中删除项目,直到堆栈为空,然后程序结束。
如果上述正确,那么为什么人们会提到控件将调用堆栈“上移”?控制肯定会向下移动到调用堆栈,直到到达底部为止。
Answers:
这种用法有两个可能的原因:
在例外情况下,控件移至调用函数/方法,并且此调用层次结构通常在主方法位于顶部的情况下可视化,而方法调用向下形成层次结构,并降低抽象级别。在此层次结构中,异常向上移动。
普通x86应用程序中的实际程序堆栈是反转的,即,它向下增长。PUSH / PUSHW / PUSHD机器码指令减少堆栈指针。其他体系结构可以共享此模型。
一切都取决于单词的定义。在本文中,“顶部”和“底部”分别是什么意思,以及在操作系统或计算机体系结构的实现上是什么意思。
我记得很久以前的事情,当时我在Commodore 64上编程。地址$ 0800(2048)和$ 9FFF(40959)之间的存储器是为BASIC程序保留的。您的BASIC程序的代码存储在较低的地址($ 0800,从该地址开始向上)处存储。该堆栈用于存储变量和子例程的返回地址,该堆栈从该范围的顶部($ 9FFF)开始,然后向较低的地址扩展。因此,在这种情况下,将堆栈向下看是合乎逻辑的,并且当您从子例程返回时,通过增加堆栈指针来丢弃该子例程的堆栈帧,以便您可以说您在“向上移动堆栈”时从子例程返回。
我不知道它如何在Windows或Intel x86处理器等现代版本中工作。也许堆栈以相反的方式工作,即,它从较低的地址增长到较高的地址。如果真是这样,那么您可能恰恰相反地使用了“顶部”,“底部”和“向上”,“向下”这两个词。
调用诸如foo(6,x + 1)之类的函数...
- 在调用者的上下文中评估实际的参数表达式,例如x + 1。
- 通过将适当的内存“本地块”推入专用于此目的的运行时“调用堆栈”,为foo()的本地用户分配内存。对于参数而非局部变量,请将步骤(1)中的值存储到foo()的局部块中的相应插槽中。
- 存储调用者的当前执行地址(其“返回地址”),并将执行切换为foo()。
- foo()以其本地块执行,可在调用堆栈的末尾方便地使用。
- 当foo()完成时,它将通过从堆栈中弹出其本地变量而退出,并使用先前存储的返回地址“返回”到调用者。现在,调用者的本地用户位于堆栈的末尾,它可以继续执行。
参考:
http://cslibrary.stanford.edu/102/PointersAndMemory.pdf(p15)
如果将堆栈概念化为自下而上的事物,例如在正常重力情况下将网球球放入其中的圆柱体,则控件会在调用函数时向上移动堆栈。功能完成后,控件将向下移动堆栈。
如果将堆栈概念化为自上而下的东西,例如同一圆柱网球,但重力相反,则控件会在调用函数时在堆栈中向下移动,并在函数完成时在堆栈中向上移动。
这些都是您脑海中的模型,本质上是完全任意的。如果愿意,可以将其概念化为并列事物,但可能无法与人沟通。我个人认为,如果A调用B且B调用C,则C是堆栈的底部(反重力现实),并且如果C中发生异常,则您想将该异常“冒泡”到A。我认为这可能是更常见的语言用法,因为感觉C是最深层的,而A是最上层的。第一个功能更直观地是我的顶部,并且每个调用的功能都会更深入。