函数的返回值存储在哪里

本文关键字:在哪里 存储 返回值 函数 | 更新日期: 2023-09-27 18:16:43

我读过几篇关于堆栈、堆以及它们如何在程序执行中使用的文章。这是其中之一。人们总是说,当调用一个函数时,它的参数被放置在堆栈中,以及局部变量(严格地说这是不正确的,正如Eric Lippert在他的帖子中所描述的,但这不是我现在的问题)。

我的问题是,从函数的返回值存储,它是如何传递给调用者?没有人说它被放在堆栈上,但仍然没有人说它不是。有人能解释一下吗?

例如,考虑以下函数:

public DateTime GetTomorrowDate()
{
    return DateTime.Now.AddDays(1).Date;
}

我的理解是,它将声明一个局部变量的返回值正确吗?如果是这样,为什么当函数返回并且它的堆栈帧被销毁时它不被销毁?它是否在调用者的堆栈帧中声明(即使调用者不使用它)?或者它可能存储在寄存器的某个地方(我不相信,因为可能没有合适大小的寄存器用于某些自定义结构)。

函数的返回值存储在哪里

我使用了几种策略。

  1. 返回值足够小,可以放入寄存器中,并作为为此目的保留的寄存器中的值从函数返回。如果需要,可以扩展到2个或更多寄存器。
  2. 返回值作为调用者的堆栈帧上的临时变量创建。然后将一个指向临时对象的引用(指针)压入堆栈,这样返回值就可以作为一个额外的out参数。在某些语言中,该变量作为命名变量('result')出现在被调用的函数中,而在其他语言中,编译器会生成一个指向该参数的移动。
  3. 创建两个局部变量,一个在函数内部,一个在函数外部。该值在函数退出时从一个复制到另一个。
  4. 返回值只是作为一个额外的参数创建。在该参数中找到的值由调用方在展开堆栈之前取出。
  5. 该值在特殊寄存器中返回,例如浮点累加器。
  6. 该值被放置在一个已知的位置(比如一个任务框架),以后可以从中检索。

可能还有其他的,但这些都是一个好的开始。


我的回答是基于想要一个常见技术的总结。在c#的上下文中,它将适用于jit生成的代码,但不适用于CIL本身。

典型的面向堆栈的VM语言(包括CIL)主要通过在函数返回时将函数值留在堆栈中来返回函数值。参数位于下面,因此在函数返回后需要进行一些堆栈清理。

正如@eric所说,很难看出这些信息何时可能有用。显然,从函数返回大值类型可能会影响性能,但这只是预期的。

CIL有很好的文档,但是JIT编译和可能的其他机制没有,这将进一步降低任何此类见解的有用性。