Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is re-using a structs own members in initialization reliable? (C99)

Tags:

c

c99

I recently saw a warning while compiling C99 code that gave me pause to question if this is undefined behavior or not.
(since I build on various platforms and only an older compiler version shows this warning).

eg:

struct Vector { float x, y; };

void func(float a) {
    struct Vector test = { .x = a, .y = test.x + 1 };
    printf("%f %f\n", test.x, test.y);
}

With Clang 3.9.0 and GCC5.3 (on Linux) the code compiles without warnings. However with Clang 3.4.1 (on FreeBSD), I get the following warning.

test.c:74:21: warning: variable 'test' is uninitialized when used within its own initialization [-Wuninitialized]
    .y = test.x + 1
     ^~~~

The code above should be the equivalent of:

void func(float a) {
    struct Vector test;
    test.x = a;
    test.y = test.x + 1;
    printf("%f %f\n", test.x, test.y);
}

It may work in one compiler yet still be undefined behavior, so my question is:

Providing the order of initialization assigns members before use.
Does C99 struct initialization re-use members and guarantee a predictable outcome?

like image 839
ideasman42 Avatar asked Dec 05 '25 10:12

ideasman42


2 Answers

The proper syntax for self-referential initialization in this case would be

struct Vector test = { .y = a, .x = test.y + 1 };

Now, the language specification says

6.7.9 Initialization

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.

While 6.7.9/19 does seem to establish temporal ordering on subobject initialization, this ordering does not in any way define the order the evaluation of individual initializer expressions. Initializer expressions can be evaluated out of order. So, it does not guarantee that test.y + 1 is evaluated after .y = a takes place. This means that your example is indeed undefined.

GCC expectedly produces a warning

'test.y' is used uninitialized in this function [-Wuninitialized]

MSVC reports

warning C4700: uninitialized local variable 'test' used
like image 61
AnT Avatar answered Dec 08 '25 00:12

AnT


struct Vector { float x, y; };

struct Vector test = { .y = a, .x = .y + 1 };

That's a syntax error. The .x = (called a designator) must be followed by an initializer, which can be either an expression (specifically an assignment-expression) or a brace-enclosed initializer-list (with an optional trailing comma).

gcc 5.3.0 in particular reports this as a syntax error:

c.c: In function 'func':
c.c:6:41: error: expected expression before '.' token
     struct Vector test = { .y = a, .x = .y + 1 };

as does clang 3.7.1:

c.c:6:41: error: expected expression
    struct Vector test = { .y = a, .x = .y + 1 };

Your .y + 1 presumably is intended to be an expression, but it isn't. There is no valid syntax to refer to a member of the object currently being initialized.

If your compiler supports this, it's a language extension, and you'll need to consult your compiler's documentation to see how it works.

Reference: N1570 section 6.7.9.

like image 25
Keith Thompson Avatar answered Dec 07 '25 23:12

Keith Thompson



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!