C 中的返回值优化和复制省略

有些人不知道可以传递和返回结构体按 C 中的值.我的问题是关于编译器在 C 中返回结构时制作不必要的副本. GCC 等 C 编译器是否使用 返回值优化(RVO) 优化还是仅 C++ 的概念?我所读到的关于 RVO 和复制省略的所有内容都与 C++ 有关.

Some people are not aware that it's possible to pass and return structs by value in C. My question is about the compiler making unnecessary copies when returning structs in C. Do C compilers such as GCC use Return value optimization(RVO) optimization or is this a C++ only concept? Everything I have read about RVO and copy elision is in regards to C++.

让我们考虑一个例子.我目前正在 C 中实现 双双数据类型(或者更确切地说是 float-float 开始,因为我发现单元测试很容易).考虑以下代码.

Let's consider an example. I'm currently implementing a double-double data type in C (or rather float-float to start with because I find it easy to unit test). Consider the following code.

typedef struct {
    float hi;
    float lo;
} doublefloat;

doublefloat quick_two_sum(float a, float b) {
    float s = a + b;
    float e = b - (s - a);
    return (doublefloat){s, e};
}

编译器会生成我返回的 doublefloat 值的临时副本还是可以省略临时副本?

Will the compiler make a temporary copy of the doublefloat value I return or can the temporary copy be elided?

C 中的命名返回值优化 (NRVO) 怎么样?我还有一个功能

What about named return value optimization (NRVO) in C? I have another function

doublefloat df64_add(doublefloat a, doublefloat b) {
    doublefloat s, t;
    s = two_sum(a.hi, b.hi);
    t = two_sum(a.lo, b.lo);
    s.lo += t.hi;
    s = quick_two_sum(s.hi, s.lo);
    s.lo += t.lo;
    s = quick_two_sum(s.hi, s.lo);
    return s;
}

在这种情况下,我将返回一个命名结构.这种情况下的临时副本可以省略吗?

In this case i'm returning a named struct. Can the temporary copy in this case be elided?

应该说明的是,这是 C 的一般问题,我在这里使用的代码示例只是示例(当我优化它时,无论如何我都会使用带有内在函数的 SIMD).我知道我可以查看汇编输出以了解编译器做了什么,但我认为这是一个有趣的问题.

It should be stated that this is a general question for C and that the code examples I have used here are only examples (when I optimize this I will be using SIMD with intrinsics anyway). I'm aware that I could look at the assembly output to see what the compiler does but I think this is an interesting question nevertheless.

推荐答案

RVO/NRVO 在 C 中的as-if"规则下是明确允许的.

RVO/NRVO are clearly allowed under the "as-if" rule in C.

在 C++ 中,您可以获得可观察到的副作用,因为您重载了构造函数、析构函数和/或赋值运算符以产生这些副作用(例如,当这些操作之一发生时打印出来),但在 C 中,您没有任何重载这些运算符的能力,并且内置的运算符没有可观察到的副作用.

In C++ you can get observable side-effects because you've overloaded the constructor, destructor, and/or assignment operator to give those side effects (e.g., print something out when one of those operations happens), but in C you don't have any ability to overload those operators, and the built-in ones have no observable side effects.

如果不重载它们,复制省略就不会产生可观察到的副作用,因此没有什么可以阻止编译器这样做.

Without overloading them, you get no observable side-effects from copy elision, and therefore nothing to stop a compiler from doing it.

相关文章