Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is copy elision in the form of named return value optimization permitted in C?

Is the following C program guaranteed to exit with 0 or is the compiler allowed to identify the objects s and t with one another as is permitted in C++ as the so-called named return value optimization (NRVO) form of copy elision?

typedef struct {
    int i, j;
    double a, b;
} S;

int result;

S test(S *q) {
    S s = {0, 0, 0, 0};
    result = &s == q;
    return s;
}

int main(void)
{
  S t = test(&t);
  return result;
}

Clang exits with 1 against my expectations, see https://godbolt.org/z/ME8sPGn3n.

(In C++, both 0 and 1 are valid outcomes due to explicit permission to perform NRVO.)

like image 963
user17732522 Avatar asked Jan 26 '26 23:01

user17732522


2 Answers

It is guaranteed to exit with 0. t and s are different objects, pointers to them can't compare equal.


About the code that you removed:

What about the following variation in which relevant lifetime considerations may be different?

From https://port70.net/~nsz/c/c11/n1570.html#6.2.4p2 :

The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

It may return 1 or 0 or perform a trap.

like image 85
KamilCuk Avatar answered Jan 29 '26 11:01

KamilCuk


Copy / move elision is a C++ concept, defined in section 15.8.3 of C++17. It allows for optimizing away constructor and destructor calls in some cases in which case the source and destination objects are one in the same:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

C has no such provision, although as of C17 it allows an object with temporary lifetime, e.g. an array contained in a struct in a non-lvalue expression, to not have a unique address. This isn't applicable to this case however.

The fact that this optimization was performed on a C program changes the observable behavior of the program in violation of the C standard. Specifically, t and s are distinct objects whose lifetime overlaps and as such they must have different addresses.

So this is a bug in clang that copy elision is being applied to a C program.

like image 27
dbush Avatar answered Jan 29 '26 13:01

dbush