C++当你从一个函数返回一个结构体时,在汇编中实际发生了什么?
我试图弄清楚如果你从函数中按值返回一个结构体,而不是返回一个指向该结构体的指针,那么在 C++ 中实际发生了什么。如果一个函数只能返回一个可以放入寄存器的值,那么在按值发送结构时如何进行通信?(我在某处读到过。)
我尝试在 Godbolt 上测试它,看看它在做什么。但我不了解大会,所以这对我有点乐观。
在我看来,在没有太多汇编知识的情况下,该函数只是更改了调用该函数之前存在的一些内存?那么return从函数中调用某些东西的概念只是一个抽象,函数只是在已经存在的内存位置设置一些字节,然后跳回到main()? 在这种情况下,根本不会复制任何内容并且返回是“免费的”?
Godbolt:返回整数
Godbolt:返回 struct{int int int}
回答
如果一个函数只能返回一个可以放入寄存器的值,那么在按值发送结构时如何进行通信?
函数可以返回任何合法返回的内容。但是,由于显而易见的原因,只能使用寄存器大小或更小的值来实现将值留在单个寄存器中的约定的return语句。一些实现允许使用多个寄存器来表示大数据类型;当然,这意味着必须编写调用程序以期望检查多个寄存器以获得完整的返回值。
机器级别的“发生了什么”不是语言标准规定的,取决于特定的编译器、它的优化能力、架构的细节等。但是,普通的简单实现平台是让调用者在堆栈上保留空间(以便它在清理之后持续)并让被调用者在那里写入数据。由于分配是静态的,通常在计算调用者的堆栈帧大小时可以简单地考虑所需的空间。该实现可能会默默地生成一个指针并将其传递给寄存器中的被调用者;或者它可能会安排每个调用者将此保留空间放在其堆栈帧中的相同位置,以便被调用者可以向堆栈指针添加偏移量以确定写入位置;或者它可能会做一些我目前没有足够创造力去想的其他事情。
有许多方法可以在机器级别处理函数之间的信息通信,这取决于机器和语言(尽管我们在进行这些讨论时通常谈论的是 C 或 C++,因为所有其他流行的选择要么在虚拟机上运行,被解释或有其他一些奇特的事情发生)。您要研究的通用术语是Application Binary Interface或 ABI。
- *its optimization capabilities* - generally no, all real-world compilers follow some standard calling convention so it's possible for code in one file to call functions in another file without having to use the same optimization options. Making the calling convention depend on a compiler's ability to spot some optimization (e.g. removing an unused struct member) is hugely problematic and isn't something compilers do. (Usually not even with whole-program link-time-optimization.)