我读过几篇关于堆栈、堆以及它们如何用于程序执行的文章。 Here是其中之一。 人们总是说调用一个函数时,它的参数和局部变量都被放置在堆栈中(严格地说这是不正确的,正如 Eric Lippert 在 his post 中所描述的,但这不是我现在的问题)。
我的问题是函数的返回值存储在哪里以及它如何传递给调用者?没有人说它放在堆栈上,但仍然没有人说它不是。谁能澄清一下?
例如,考虑以下函数:
public DateTime GetTomorrowDate()
{
return DateTime.Now.AddDays(1).Date;
}
我的理解是它将为返回值声明一个局部变量是否正确?如果是这样,为什么当函数返回时它没有被销毁并且它的堆栈框架被销毁了?它是否在调用者的堆栈帧中声明(即使它没有被调用者使用)?或者它可能存储在寄存器中的某个地方(我不相信,因为对于某些自定义结构可能没有合适大小的寄存器)。
最佳答案
有几种策略(我已经使用过)。
- 返回值足够小,可以放入一个寄存器中,并且作为一个值从函数返回到一个为该目的保留的寄存器中。如果需要,这可以扩展到 2 个或更多寄存器。
- 返回值作为临时变量创建在调用者 的栈帧中。然后将临时对象的引用(指针)压入堆栈,以便返回值充当额外的输出参数。在某些语言中,该变量作为命名变量(“结果”)出现在被调用函数中,而在其他语言中,编译器会生成对该参数的移动。
- 创建了两个局部变量,一个在函数内部,一个在函数外部。在函数退出时将值从一个复制到另一个。
- 返回值只是作为一个额外的参数创建的。在该参数中找到的值在展开堆栈之前由调用者提取。
- 值在“特殊”寄存器中返回,例如浮点累加器。
- 该值被放置在一个已知位置(例如任务框架),以后可以从中检索它。
可能还有其他的,但这是一个好的开始。
我的回答是基于阅读这个问题,因为它想要一个常用技术的总结。在 C# 的上下文中,它适用于 JIT 生成的代码,但不适用于 CIL 本身。
典型的面向堆栈的 VM 语言(包括 CIL)主要通过在函数返回时将它们留在堆栈中来从函数返回值。参数位于其下方,因此在函数返回后需要进行一些堆栈清理。
正如@eric 所说,很难看出这些信息何时有用。显然,从函数返回大值类型可能会对性能产生影响,但这只是预期的结果。
CIL 有很好的文档记录,但 JIT 编译和可能的其他机制没有,这将进一步降低任何此类见解的有用性。
关于c# - 函数的返回值存储在哪里,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25162192/