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/58439905/

相关文章:

c# - C# 是否具有零成本抽象?

windows - 通用调用约定如何处理 AVX 寄存器?

c - 使用 calloc() 设置 char 数组,完成后也是 "freeing"数组

有人可以解释 C 如何处理 for 循环中的结构声明吗? (见例子)

c - 为什么我的逆波兰表示法输出错误的输出

c - 如果 if 语句返回相同的内容,C 编译器是否会合并它们?

visual-c++ - MSVC 2017 是否支持自动 CPU 调度?

c - 为什么 `main` 以 `ret` 而不是 `ret 4` 结尾?

c++ - 与使用早期版本的 Visual Studio 构建的第 3 方静态库链接时出错

c - 如何打印void * ioremap_nocache()的返回值?