Consider the following two examples:
1.
union test{
struct {
int a;
int b[];
};
};
int main(void){
union test test;
test.a = 10;
printf("test.b[0] = %d", test.b[0]); //prints 0, UB?
}
DEMO
2.
#include <stdio.h>
union test{
int a;
int b[]; //error: flexible array member in union
};
int main(void){
union test test;
test.a = 10;
printf("test.b[0] = %d", test.b[0]);
}
DEMO
The behavior is unclear. I expected the examples would behave the same (i.e. the first example would also fail to compile) since 6.7.2.1(p13)
:
The members of an anonymous structure or union are considered to be members of the containing structure or union.
So I interpreted the wording as if a union
contains an anonymous struct
as a member the members of the anonymous struct
would be considered as members of the containing union
.
Question: Why does the first example compile fine instead of failing as the second one?
A structure can be nested inside a union and it is called union of structures. It is possible to create a union inside a structure.
An anonymous union is a union without a name. It cannot be followed by a declarator. An anonymous union is not a type; it defines an unnamed object. The member names of an anonymous union must be distinct from other names within the scope in which the union is declared.
Flexible array members are a special type of array in which the last element of a structure with more than one named member has an incomplete array type; that is, the size of the array is not specified explicitly within the structure.
// Anonymous union example union { char alpha; int num; }; // Anonymous structure example struct { char alpha; int num; }; Since there is no variable and no name, we can directly access members. This accessibility works only inside the scope where the anonymous union is defined.
NOTE: this answer has been substantively modified since first being written, reflecting a change to the committee's position after publication of the documents on which the original version of the answer relied.
The members of an anonymous structure or union are considered to be members of the containing structure or union.
This is a tricky provision to interpret, and indeed it has been the subject of at least two defect reports against the standard. The intention, as supported by the committee in its response to DR 499 is that anonymous structures are treated for layout purposes as if the structure itself were the member of the containing structure or union, but access to its members is expressed as if they were members of the containing structure or union.
The accepted position on DR 502, on the other hand, holds that even an anonymous struct containing a flexible array member as its only member is allowed if it is the last member of the structure (not union) containing it, and at least one other precedes it.
I find those a bit inconsistent, but the unifying theme across them seems to be that the intent of the standard in this area comes down to layout. A flexible array member inside an anonymous struct is allowed as long as it comes at the end of the layout of the innermost named structure or union, which must have non-zero size from consideration of the other members, taking into consideration the fact that members of an anonymous struct do not overlap, regardless of whether the anonymous struct appears inside a union.
The proposed committee response to DR 502 (which differs from its initial position) is consistent with that. It holds that anonymous structures inside a structure or union must obey the same rules as other structures with respect to flexible array members, notwithstanding the provision you ask about.
The committee does not appear to have decided the specific question you asked, but the theme of its decisions seems clear: the "considered to be members of the containing structure or union" wording is intended to be interpreted narrowly, as a statement only about the syntax for accessing members of anonymous structures and unions. Thus, that provision has nothing to say about whether anonymous structures may contain FAMs, and the general rules about when and where they may do apply. Those rules allow your first case.
The second case fails to compile, because flexible array member is a property of a structure type, not for unions. That's straightforward.
Next, in the first case, trying to access b[0]
would be undefined behavior, as no memory has been allocated for that.
Quoting C11
, §6.7.2.1/P18
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. [...] If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
That said,
The members of an anonymous structure or union are considered to be members of the containing structure or union.
That is for the access purpose, the layout remains unchanged. See, in your first example, you're accessing a
(and b
) as if they are direct members of the union.
To clarify,
#include <stdio.h>
union test{
struct {
int p;
float q;
} t; //named structure member
struct {
int a;
int b[];
};
char pqr;
};
int main(void){
union test test;
test.t.p = 20; // you have to use the structure member name to access the elements
test.pqr = 'c'; // direct access, as member of union
test.a = 10; // member of anonymous structure, so it behaves as if direct member of union
}
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