If it weren't for the array member, the return would be an "rvalue", a value that is just a copy of the value that you have inside the return
expression. If you have
struct toto {
double a;
};
struct toto g(void) {
struct toto retval = { 0.0 };
...
return retval;
}
int main(void) {
printf("%g\n", g().a);
}
The argument of the printf
call sees a copy of the variable retval
that is used inside the function. g().a
calls the function and uses the .a
field of the return value.
This return value is and
entity that is not an object but only lives because of its "value", called rvalue in the C jargon. It only can be found on the RHS of an assignment, thus the "r" in "rvalue".
The case that you are giving is actually specially treated, because a "value" is not sufficient for all use cases of the array. So this generates a so-called "object with temporary lifetime". This is needed because if you'd do ret_stupid().v[2]
the []
operator wants to have a pointer, and a pointer can only point to an object, not a value.
These objects only "live" inside the expression that contains the function call, and even though they are not const qualified you are not allowed to modify them.
So all in all, this is a corner case of C, and you shouldn't abuse it.