drigoSkalWalker
drigoSkalWalker

Reputation: 2812

Nested braces and designated Initializers

Why I need the nested braces to compile this code?

#include <stdio.h>
#include <stdlib.h>

typedef union TEST TEST;

union TEST {
    int type;
    char *things;
 };


int main () {

    TEST test[] = {1, 2, .things = NULL}; // Compile time error

    TEST test[] = {1, 2, {.things = NULL}}; // Works, but I didn't check at run time

    return 0;
}

Why the first assignment doesn't works?
Why the inner braces are needed?
Are there any way to work in the first assignment? Without the inner braces?

Thank you!

Upvotes: 1

Views: 1041

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222272

In summary: {1, 2, .things = NULL} attempts to initialize an element of the array test that is named things, but the array does not have an element named things, so this is invalid. In contrast, {1, 2, {.things = NULL}} attempts to initialize a member of the second element of the array that is named things, and the second element of the array is a union that does have a member named things, so this is valid.

Per C 2011 (N1570) 6.7.9 17:

Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.

There is more in subsequent paragraphs about how the current object is handled, but this is enough for now. In the brace-enclosed initializer list, 1 is a simple initializer; it does not have any designations. So it initializes a subobject of the array, which is an array element. Similarly, 2 initializes another element. Then we have .things = NULL. This does have a designator, .things.

According to the quoted paragraph, this designator, .things causes initialization of the subobject described by .things. But there is nothing in the array that is designated by .things. It is only an array with indexed elements, designated by [index]. It does not have any members designated by .thigns. So there is an error.

In the second list, where additional braces are used, paragraph 20 applies:

If the aggregate or union contains elements or members that are aggregates or unions, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the contained union.…

In this case, {.things = NULL} begins with a left brace. This says that the initializers contained within the braces initialize the current object of the larger list. So they are initializing the next element of the array (the element with index 2). Any element of the array is a union with a member named things, so .things does designate a subobject in it, and this syntax is acceptable.

Upvotes: 2

Sneftel
Sneftel

Reputation: 41454

The fact that you don't need inner braces on the first two elements is an odd detail in the syntax for initializer lists, which allows a union to be initialized as its first element. I would suggest using braces and designation for all the initializers in the list, not just .things.

Upvotes: 3

Related Questions