GCC and Clang both allow a designated initializer to refer to a member of the struct or array being initialized, but is this legal and well defined behaviour?
The following code example compiles and runs for both GCC and Clang and outputs { .a = 3, .b = 6, } in both cases:
#include <stdio.h>
typedef struct
{
int a;
int b;
} foo;
int main()
{
foo bar = {
.a = 3,
.b = bar.a + 3,
};
printf("{ .a = %d, .b = %d, }\n", bar.a, bar.b);
return 0;
}
GCC generates the following output (Compiler Explorer link) for the designated initialization which shows that the operation is safe for this example:
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 16], 3
mov eax, dword ptr [rbp - 16]
add eax, 3
mov dword ptr [rbp - 12], eax
Section 6.7.8 of the draft C99 spec discusses this, but I don't see how it defines this behaviour one way or another.
In particular, point 19 suggests that initialization happens in the specified order, but point 23 mentions side effects having an unspecified order. I'm unsure if the data being written to the struct is considered a side effect.
- The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.
- The order in which any side effects occur among the initialization list expressions is unspecified
You're quoting an old version of the C standard. Current drafts (since C11) have, for point 23:
The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.
I take that to mean that the compiler can choose to evaluate a particular initialization expression at any time prior to the moment at which that expression is used, which means that it might happen before or after the element it refers to has been initialised.
That being the case, using a (possibly) uninitialised element of the same aggregate object in an initialisation expression must result in an indeterminate value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With