【问题标题】:how does the function return type works as shown below? [closed]函数返回类型如何工作,如下所示? [关闭]
【发布时间】:2019-12-13 01:37:44
【问题描述】:

我想知道是否有人可以帮助详细解释函数返回类型的工作。

例如,如果返回类型是int,它是如何保存的?在 64 位 CPU 中,假设寄存器是 64 位,那么它如何保存在一个寄存器中?低8位?

那么如何保存 128 位的 double double 呢?在两个寄存器中?

那么代码的其他部分是如何知道返回值在哪里的呢?

感谢您的帮助,

布赖恩

【问题讨论】:

  • google 术语“ABI”和“调用约定”

标签: c


【解决方案1】:

这是一个很好的问题,因为答案揭示了很多关于幕后发生的事情,尽管它基本上不会影响您编写软件的方式。

首先:答案在很大程度上取决于您使用的 CPU,因为每种架构都有自己的处理寄存器和返回值等的约定。正如上面评论中提到的,“ABI”是应用程序二进制接口定义了一组每个人都必须同意的约定。

ABI 是您深入了解特定平台的方式,而这篇文章充其量只是路过。

对于简单的返回 - 例如一个整数 - 几乎所有 CPU 都有一个“明显”的寄存器用于此,在 Intel x86 平台上它是 eax,对于 x64 它是 rax

这本质上是许多处理器(至少在概念上)共享的“A”寄存器,并且函数/子例程将返回值存储在此处以供调用者使用。

在这些情况下,调用者在这个“A”寄存器中找到的任何东西都被认为是返回,但它无法知道子程序是否故意在此处放置一个值以进行返回,或者它是否只是计算中的一些随机剩余.

这有一个奇怪的副作用,即一个不会有意返回值的函数在返回时会“返回”eax 寄存器中发生的任何内容。有时这是计算的结果,有时是在返回之前调用的子函数的返回值。

int myfunc()
{
   .. do some stuff
   int x = 4 * other_function();
   // note no "return"
}

可能是计算出的x 被“返回”只是因为它恰好落在了 A 寄存器中,但不要指望它:它本质上是一个错误。它也可能是其他一些值。一个好的编译器会警告你这样的狡猾的事情:关于这些神秘回报的问题一直存在于 SO 上。

当然,这并不总是那么简单:您不能将 128 位值放入 64 位寄存器,因此返回 double(或 long long)的函数必须采取其他规定。

对于整数值,许多架构都同意一起使用两个寄存器,对于浮点值,可以使用一组单独的浮点寄存器,调用者同意查阅。

调用者和被调用者就它们的去向达成一致至关重要

一种特殊情况是返回一个大项目,例如一个结构。这不是一个好主意,大多数人都不推荐它(尽管合法),而且很明显,返回(比如说)488 字节结构将不适合大多数架构的寄存器。

诀窍是调用者为完整的返回值分配空间,然后将该返回区域的地址在隐藏参数中传递给函数(有时在“A”寄存器中)。被调用者知道将计算结构复制到该隐藏指针指向的内存中。

参考:How do C compilers implement functions that return large structures?

如前所述,这只是路过,您确实必须研究您正在使用的处理器的架构,但这里最重要的事实是:这些是约定,这意味着它们只是每个人都同意的东西,而不是一些固有的“正确”答案。

【讨论】:

  • Register A 通常称为累加器,因为它累加操作的结果。因此,在某些架构上,它的助记名称是 ACC。其他一些像 PIC 将其称为 W 用于 工作寄存器
  • 谢谢! eax 和 rax 是什么? arm架构怎么样?谢谢你,布赖恩
猜你喜欢
  • 1970-01-01
  • 2023-03-28
  • 2023-03-06
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
相关资源
最近更新 更多