使用 `` 在 C++ 中聚合初始化联合
Posted
技术标签:
【中文标题】使用 `` 在 C++ 中聚合初始化联合【英文标题】:Aggregate initialization of a union in C++ with ``使用 `` 在 C++ 中聚合初始化联合 【发布时间】:2021-10-23 03:26:44 【问题描述】:在下面的程序中,联合 U
有两个字段 a
和 b
,每个字段都有不同的默认值。如果使用聚合初始化创建U
类型的变量 联合的值和活动成员是什么?
#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;
令人惊讶的是编译器在这里出现了分歧:Clang 打印 1
和 GCC 打印 0
,演示:https://gcc.godbolt.org/z/8Tj4Y1Pv1
其中一个编译器是否存在错误或此处的行为未由标准定义?
【问题讨论】:
当你初始化u
时,你正在做value initialization。而且由于U
不是类类型,所以会导致u
成为zero initialized。
令人惊讶的是编译器在这里出现分歧:Clang 打印 1 和 GCC 打印 0 - 似乎有缺陷,应该是 0
@Someprogrammerdude U
是一个类类型,它是联合聚合类。注意规范性术语“non-union aggregate”,例如在 [dcl.init.aggr]/5 中使用。因此,这是聚合初始化,并且 [dcl.init.aggr]/5 适用(/5.5 表示 U u;
,然后 /5.1 表示联合的第一个数据成员 a
)。
【参考方案1】:
Clang 正确,GCC 错误
根据[dcl.init.aggr]/1:
聚合是一个数组或一个类([class])
(1.1) 没有用户声明或继承的构造函数 ([class.ctor]), (1.2) 没有私有或受保护的直接非静态数据成员 ([class.access]), (1.3) 没有虚函数 ([class.virtual]),并且 (1.4) 没有虚拟、私有或受保护的基类 ([class.mi])。
A
、B
和 U
都是聚合类,虽然前面是 非联合 聚合类,前者不符合条件。
根据[dcl.init.aggr]/5 [强调我的]:
对于非联合聚合,每个不是显式 初始化元素的初始化如下:
(5.1) 如果元素具有默认成员初始化程序 ([class.mem]),则从该初始化程序初始化元素。 (5.2) 否则,如果元素不是引用,则从空的初始化列表 ([dcl.init.list]) 复制初始化该元素。 (5.3) 否则,程序格式错误。如果聚合是一个联合并且初始化列表为空,那么
(5.4) 如果任何变体成员具有默认成员初始化程序,则该成员从其默认成员初始化程序初始化; (5.5) 否则,联合体的第一个成员(如果有)将从空的初始化列表复制初始化。
这样
U u;
是聚合初始化,结果是联合类的第一个数据成员,即A
类型的数据成员a
(这是一个非联合聚合类),从一个空的初始化列表。由于A
类型的单个数据成员x
有一个默认的成员初始化器,那么根据上面的[dcl.init.aggr]/5.1,数据成员x
由它的默认成员初始化器初始化。
因此,Clang 是正确的,而 GCC 是错误的。
GCC 错误报告
Bug 102013 - Incorrect aggregate initialization of union【讨论】:
MSVC 也打印 0 @MarcinPoloczek 我通常对 MSVC 在 GCC 和 Clang 不同意的语言极端情况下的行为没有什么价值。在这种特殊情况下,afaict Clang 正在按照标准实现正确的行为。 是的,您的答案似乎是正确的。我错过了细节。我已经删除了我的帖子。以上是关于使用 `` 在 C++ 中聚合初始化联合的主要内容,如果未能解决你的问题,请参考以下文章