In the following program the union U
has two fields a
and b
, each with distinct default value. If one creates a variable of type U
using aggregate initialization {}
what are the value and the active member of the union?
#include <iostream>
struct A { int x = 1; };
struct B { int x = 0; };
union U {
A a;
B b;
};
int main() {
U u{};
std::cout << u.a.x;
}
Surprisingly the compilers diverge here: Clang prints 1
and GCC prints 0
, demo: https://gcc.godbolt.org/z/8Tj4Y1Pv1
Is there a bug in one of the compilers or the behavior here is not defined by the standard?
C allows you to initialize a union in two ways: Initialize a union by initializing the first member of a union. Or initialize a union by assigning it to another union with the same type.
An initializer for a structure is a brace-enclosed comma-separated list of values, and for a union, a brace-enclosed single value. The initializer is preceded by an equal sign ( = ).
Initializing Union Variable union data { int var1; double var2; char var3; }; union data j = {10}; This statement initializes the union variable j or in other words, it initializes only the first member of the union variable j .
A union can be initialized on its declaration. Because only one member can be used at a time, only one can be initialized. To avoid confusion, only the first member of the union can be initialized.
As per [dcl.init.aggr]/1:
An aggregate is an array or a class ([class]) with
- (1.1) no user-declared or inherited constructors ([class.ctor]),
- (1.2) no private or protected direct non-static data members ([class.access]),
- (1.3) no virtual functions ([class.virtual]), and
- (1.4) no virtual, private, or protected base classes ([class.mi]).
A
, B
and U
are all aggregate classes, although the prior to are non-union aggregate classes, which the former does not qualify as.
As per [dcl.init.aggr]/5 [emphasis mine]:
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
- (5.1) If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
- (5.2) Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
- (5.3) Otherwise, the program is ill-formed.
If the aggregate is a union and the initializer list is empty, then
- (5.4) if any variant member has a default member initializer, that member is initialized from its default member initializer;
- (5.5) otherwise, the first member of the union (if any) is copy-initialized from an empty initializer list.
Thus
U u{};
is aggregate initialization, with the result that the first data member of the union class, namely the data member a
of type A
(which is a non-union aggregate class), is copy-initialized from an empty initializer list. As the single data member x
of the type A
has a default member initializer, then as per [dcl.init.aggr]/5.1 above, the data member x
is initialized by its default member initializer.
Thus, Clang is correct, and GCC is wrong.
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