Yes, it's undefined behavior. The relevant section of the C17 standard is "6.2.4 Storage durations of objects":
The lifetime of an object is the portion of program execution during which storage is guaranteed
to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value
throughout its lifetime.34) If an object is referred to outside of its lifetime, the behavior is undefined.
A non-lvalue expression with structure or union type, where the structure or union contains a
member with array type (including, recursively, members of all contained structures and unions)
refers to an object with automatic storage duration and temporary lifetime.36) Its lifetime begins
when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends
when the evaluation of the containing full expression ends.
The expression get(0)
is not an lvalue, and struct test
contains c_arr
, a member with array type, so it has temporary lifetime. This means that return *a;
is UB because it accesses it outside of its lifetime.
Also, a big hint that this isn't allowed is that had you used char c;
instead of char c_arr[1];
, then char* a = &get(0).c;
would have been a compile-time error, since you can't take the address of an rvalue, and what you wrote is basically morally equivalent to trying to do that.
I filed GCC bug 101358 and LLVM bug 51002 about not receiving warnings for this.