The structure returned by foo
is just a value (also called an rvalue). It is not an object and does not have any lifetime.
Consider a function int foo(void) { return 3; }
. This returns an int
value of 3, and we would not expect to be able to take its address, as in printf("%p", (void *) &foo());
. The 3 is just a value used in the computer with no associated storage.
Similarly, given struct S { int x, y; }
, struct S foo(void) { return (struct S) { 3, 4 }; }
returns a struct S
value containing 3 and 4. Although we often think of structures as layouts of memory, the C standard treats this return value as just a value. It is a compound value, having multiple parts, but it is just a value with no associated storage. It is not an object in the C model.
Also similarly, given struct S { int x, y[1]; }
, struct S foo(void) { return (struct S) { 3, { 4 } }; }
returns a struct S
value containing 3 and an array containing 4. Here the C standard painted itself into a corner. It wanted to support returning structures from functions, but, when you access an array, as in foo().y[0]
, the rule currently in C 2018 6.3.2.1 3 says the array is converted to a pointer to its first element. A pointer has to point to storage, so there has to be some object to point to. I suppose one solution might have been to say you cannot use arrays within such structure values individually. (You could use the return value by copying it into an object with struct S x = foo();
and then using x
.) However, the solution the C committee adopted was to define a temporary lifetime for such structures. Their definition for that, in C 2018 6.2.4 8, defines a temporary lifetime only for structures and unions that contain an array member.
However, in your code, this is not a concern. Because your foo(2, 4)
returns a value, you can use that value as you desire; foo(2, 4).x
works because it takes the x
member of the value. It does not need to worry about the lifetime of any object because there is no object involved.