有些人不知道它是possible to pass and return structs by value in C。我的问题是关于编译器在C中返回结构时制作不必要的副本。诸如GCC之类的C编译器使用Return value optimization(RVO)优化还是仅仅是C ++概念?我读到的关于RVO和copy elision的所有内容都与C ++有关。
让我们考虑一个例子。 我目前正在C中实现double-double data type(或者更确切地说是float-float,因为我觉得单元测试很容易)。请考虑以下代码。
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
值,还是可以省略临时副本?
C中命名的返回值优化(NRVO)怎么样?我有另一个功能
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;
}
在这种情况下,我将返回一个命名结构。在这种情况下临时副本可以省略吗?
应该说这是C的一般问题,我在这里使用的代码示例仅仅是示例(当我优化它时,无论如何我将使用带有内在函数的SIMD)。我知道我可以查看汇编输出以查看编译器的功能,但我认为这是一个有趣的问题。
答案 0 :(得分:41)
在C中的“as-if”规则中明确允许RVO / NRVO。
在C ++中,您可以获得可观察的副作用,因为您已经重载了构造函数,析构函数和/或赋值运算符以提供这些副作用(例如,当其中一个操作发生时打印出来的东西),但在C中你没有任何能力重载这些操作符,内置的操作符没有可观察到的副作用。
如果没有重载它们,你就不会从复制省略中获得可观察到的副作用,因此没有什么可以阻止编译器这样做。
答案 1 :(得分:34)
为C ++提供很多功能的原因是因为在C ++中,RVO有副作用(即不调用临时对象的析构函数,也不调用生成对象的复制构造函数或赋值运算符)。
在C中,没有可能的副作用,只有潜在的性能改进。我认为没有理由不能通过某些编译器执行这样的优化。至少,在标准中没有任何禁止它的内容。
无论如何,优化是编译器和优化级别相关的,所以我不打赌它用于关键代码路径,除非使用的编译器定义良好且预计不会改变(通常情况仍然如此)。 p>