31 ms·
Return value optimization is absolutely allowed in C, and ~all compilers do it. It's not commonly talked about because in C, there can be no side-effects when c
by stephencanon 8y ago
Return value optimization is absolutely allowed in C, and ~all compilers do it. It's not commonly talked about because in C, there can be no side-effects when constructing or copying a struct, so there's nothing to discuss. It just happens automatically and there's no observable change in program behavior.
- ajross 8y agoC compilers can do copy ellision when inlining code as long as the result is identical. That's not quite the same thing as RVO, which deliberately relaxes the notion of "identical result" such that it's possible to write C++ code to detect whether or not RVO was actually performed. That's not possible in C (or shouldn't be).
- stephencanon 8y agoIt's possible that I'm missing something, but I believe that the result is necessarily identical in C, because there can be no observable side-effect of a struct copy in the C abstract machine.
- SidiousL 8y agoI tried to find an example that contradicts what you said, but I can't find any. Here's an online example which can be compiled as both C and C++ and I obtain exactly the same assembly using both clang and gcc. Maybe somebody can tweak this example to force the C compiler not to perform the optimization. https://godbolt.org/g/7Ewun7 https://godbolt.org/g/7Ewun7
- BeeOnRope 8y agoSee my reply to the parent poster for an example where RVO applies in C++ but not C, leading to better code in the C++ case. The key is to let the address of the objects involved escape: otherwise "as if" will let C (and C++ even without RVO) optimize away the copies anyways, since they are not observable in that case.
- 8xde0wcNwpslOw 8y agoDon't quote me on this, but I think padding bytes might have different values in certain cases.
- a1369209993 8y agoI'm fairly sure it's always undefined behavior to observe those differences, so while it's possible in practice, it'd never work in theory.
- e12e 8y ago> while it's possible in practice, it'd never work in theory. Hah, sounds like you nailed the emergent philosophy of C there... :-)
- BeeOnRope 8y agoNo, it is not necessarily identical in C, because even though you don't have constructors or destructors, you can make an address comparison to check whether two objects are identical. For example the following code: https://godbolt.org/g/ikD6bi https://godbolt.org/g/ikD6bi where the address of the caller's variable that will take the return value is passed along to the function returning it. Within the callee, f1 and f2 must be different objects in C, but not in C++. All decent compilers compile this in C++ with only a single object, so sink() will receive identical objects. Most compilers "deoptimize" this in C since sink cannot receive identical objects: two objects are created so f1 and f2 have different addresses, and a copy is performed from f2 to the return value f1. Due to a bug, clang mis-compiles this and applies the C++ RVO to C. So you maybe you are right: you can get RVO in C, but only due to a compiler bug!
- stephencanon 8y agoAh, yes, that's a nice example.
- jcelerier 8y agoNo, C has much less RVO allowed than C++. I provided an example of this here the last time : https://news.ycombinator.com/item?id=17216250 https://news.ycombinator.com/item?id=17216250
- stephencanon 8y agoFrom what I can see, the example you list there is just a missed optimization in the C compilers you tested. It's absolutely allowed, and clang trunk is happy to do it in C-mode, for example.
- petters 8y agoThere could be some more fundamental differences due to the requirement that different objects require different pointers that prevent some optimizations.
- BeeOnRope 8y agoNo C doesn't have RVO in the C++ sense. Sure C can optimize the copies implied by "returning values" in the same way they can optimize other copies or anything at all, if the observable behavior is the same, due to "as if" - but that's not RVO (as it is discussed in C++). It doesn't even need a special name: it's just plain old optimization. RVO is a very specific optimization that has its own language in the standard (which is notable since the standard is pretty much silent on the vast majority of optimizations) and it is special precisely because it allows the optimization to occur even if it changes observable behavior. C does not have it, and compilers must compile the some code more conservatively because of it: e.g., if the address of return values escape in the caller and/or callee, a C compiler must ensure that the program always observes distinct addresses for distinct objects in the source, but in C++ one is free to observe that two apparently different objects are the same. Now, sure, at least 90% of actual RVO is about eliminating constructors and destructors with side effects - which C doesn't have and so RVO simply doesn't apply most of the time: but one shouldn't conclude that "C has RVO", rather "C mostly doesn't need RVO, and in the cases were it could use it, it is not allowed and must be more conservative than C++".