C++ 当您 return 来自函数的结构时,汇编中实际发生了什么?

C++ What actually happens in assembly when you return a struct from a function?

我想弄清楚如果你 return 从函数中按值构造一个结构,而不是 return 一个指向该结构的指针,那么在 C++ 中实际发生了什么。如果一个函数只能 return 一个可以放入寄存器的值,那么当它按值发送时,结构如何通信? (我在某处读到过。)

我尝试在 Godbolt 上测试它,看看它在做什么。但是我不懂汇编,所以我有点乐观。

在没有太多汇编知识的情况下,我确实认为该函数只是更改了调用该函数之前存在的一些内存?那么 return 从函数中获取某些东西的概念只是一个抽象,函数只是在已经存在的内存位置设置一些字节,然后结束跳回到 main()?在这种情况下,根本不会复制任何内容, return 是 “免费”?

Godbolt: Return int

Godbolt: Return struct{int int int}

How is a struct communicated when its sent by value if a function can only return a value that can fit in a register?

函数可以 return 任何对 return 合法的东西。但是,只有寄存器大小或更小的值才能用于实现 return 语句 ,按照在单个寄存器 中留下值的约定,原因很明显。一些实现允许使用多个寄存器来表示大数据类型;当然,这意味着必须编写调用程序以期望检查多个寄存器以获得完整的 return 值。

语言标准并未指定机器级别的“发生了什么”,它取决于特定的编译器、其优化能力、体系结构的细节等。但是,直截了当[= 普通 平台上的 22=] 实现是让调用者在堆栈上保留 space(以便它在清理之后持续存在)并让被调用者将数据写入那里。由于分配是静态的,通常在为调用者计算堆栈帧的大小时可以简单地考虑所需的 space。该实现可能会默默地生成一个指针并将其传递给寄存器中的被调用者;或者它可能安排每个调用者将这个保留的 space 放在其堆栈帧中的相同位置,以便被调用者可以向堆栈指针添加偏移量以确定写入的位置;或者它可能会做一些其他我目前还没有足够的创意去想的事情。

有许多方法可以在机器级别处理函数之间的信息通信,这取决于机器和语言(尽管我们在进行这些讨论时通常谈论的是 C 或 C++,因为所有其他流行的选择要么在 VM 上 运行,要么被解释,要么有一些其他奇特的事情正在进行)。您要查看的通用术语是 Application Binary Interface 或 ABI。

所以我花了几个小时玩 Godbolt 的编译器资源管理器并阅读直到找到实际答案。

我收集到的是:

  1. 如果该值适合寄存器,它将作为 return 值保留在寄存器中。
  2. 如果该值适合 2 个寄存器,则保留在 2 个寄存器中。
  3. 如果值大于这个值,调用者在自己的堆栈中保留内存,函数直接写入调用者的堆栈。

G++ 和 Clang 都做同样的事情,这是在 x86_64 上测试的。