I was reading about compound literals, and I saw that they are l-values. So I suspected that you can assign them, so I did an experiment and I noticed that this compiles without warnings with gcc -Wall -Wextra -pedantic
:
struct foo {
int x;
int y;
};
int main(void) {
(struct foo){0,0} = (struct foo){1,1};
}
It got me confused, because I really cannot see any situation at all where this could be useful. When would you ever want to assign anything to a compound literal?
Or is it one of the usual undefined behaviors? Because it looks very much alike modifying string literals. This compiles without warnings with the same parameters as above:
struct foo *ptr = &(struct foo){0,0};
*ptr = (struct foo){1, 1};
char *str = "Hello";
*str = 'X'; // Undefined behavior
Modifying the string is undefined behavior according to C standard 6.4.5.7
What is the goal of compound literals?
The goal is to create a fully usable on the stack without providing a name for it.
Does "fully usable object on the stack" entail being an lvalue?
Yes. One of the typical uses for compound literals is to have their address taken and being passed on to some function. The goal is, that, whenever I have a function that takes a
Foo* fooPtr
, I can supply the argument as a compound literal&(Foo){...}
. Since I'm taking the address and need to pass the non-const pointer on to the function, the compound literal must be an lvalue.Note that the function can then assign to the object with a simple
*fooPtr = (Foo){...};
. Code like this is very typical for constructors, or functions that reset an object. The function does not know whetherfooPtr
points to a compound literal, a named variable, or a memory chunk on the heap. The assignment is legal for all these cases.You see, the fact that you can assign to a compound literal is simply a side effect of compound literals being lvalues. And compound literals are only really useful as an inline, on-the-fly object creation construct if they are really lvalues.