c - C 编译器如何实现返回大型结构的函数?

标签 c compiler-optimization calling-convention abi compiler-theory

函数的返回值通常存储在堆栈或寄存器中。但是对于大型结构,它必须在堆栈上。在真正的编译器中必须为此代码进行多少复制?还是优化掉了?

例如:

struct Data {
    unsigned values[256];
};

Data createData() 
{
    Data data;
    // initialize data values...
    return data;
}

(假设函数不能内联..)

最佳答案

无;没有副本完成。

调用者的 Data 返回值的地址实际上作为隐藏参数传递给函数,createData 函数只是简单地写入调用者的堆栈帧。

这被称为 named return value optimisation .另见 c++ faq on this topic .

commercial-grade C++ compilers implement return-by-value in a way that lets them eliminate the overhead, at least in simple cases

...

When yourCode() calls rbv(), the compiler secretly passes a pointer to the location where rbv() is supposed to construct the "returned" object.

您可以通过将带有 printf 的析构函数添加到您的结构来证明这已完成。如果此按值返回优化正在运行,则应仅调用一次析构函数,否则调用两次。

您还可以检查程序集以查看是否发生了这种情况:

Data createData() 
{
    Data data;
    // initialize data values...
    data.values[5] = 6;
    return data;
}

这是程序集:

__Z10createDatav:
LFB2:
        pushl   %ebp
LCFI0:
        movl    %esp, %ebp
LCFI1:
        subl    $1032, %esp
LCFI2:
        movl    8(%ebp), %eax
        movl    $6, 20(%eax)
        leave
        ret     $4
LFE2:

奇怪的是,它在堆栈上为数据项 subl $1032, %esp 分配了足够的空间,但请注意它采用堆栈上的第一个参数 8(%ebp) 作为对象的基地址,然后初始化该项目的元素 6。由于我们没有为 createData 指定任何参数,这很奇怪,直到您意识到这是指向父数据版本的 secret 隐藏指针。

关于c - C 编译器如何实现返回大型结构的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2155730/

相关文章:

具有多个文件的项目中的 CMakeLists.txt

c - "Segmentation Fault (core dumped)"是什么?为什么它会在我的输出中返回?

c - lang使用的调用约定是什么?

compiler-construction - MIPS 编译器中的寄存器——使用哪个?

c - 可变参数和 x64

c++ - 将现有函数复制到内存缓冲区

c++ - 将自定义标签添加到 TIFF 文件

c - if 语句、函数评估和编译器优化

c++ - 仅在打开编译器优化的情况下,某些地方的缓冲区溢出

c - 如何知道任何库函数(中止)调用是否在源代码中多次使用?