Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a designated initializer legally refer to the variable it's initializing in C99?

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.

  1. 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.
  1. The order in which any side effects occur among the initialization list expressions is unspecified
like image 838
Andy Stanton Avatar asked Dec 05 '25 06:12

Andy Stanton


1 Answers

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.

like image 89
rici Avatar answered Dec 07 '25 21:12

rici



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!