Reputation: 2812
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
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
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