读取与活动变体类型相同的联合体的另一个变体成员是否会导致 UB?

jac*_*k X 21 c c++ language-lawyer

union A{
  int a;
  int b;
};
int main(){
  A u = {.a = 0};
  int r = u.b; // #1 Is this UB?
}
Run Code Online (Sandbox Code Playgroud)

[class.union] 说

在联合中,如果非静态数据成员的名称引用其生命周期已开始且尚未结束的对象 ([basic.life]),则该非静态数据成员处于活动状态。联合类型对象的最多一个非静态数据成员在任一时刻可以是活动的,即任一时刻联合体中最多可以存储一个非静态数据成员的值。

在此示例中,仅A::a处于活动状态,然后 [basic.life] p7 表示

如果出现以下情况,则程序具有未定义的行为:

  • 左值用于访问对象,或者

#1尝试访问生命周期尚未开始的对象。此访问是否会导致 UB,如果是,此要求是否过于严格?

顺便说一句,C 标准在此示例中是否提出了相同的要求?或者说,在这种情况下,C 有更宽松的要求吗?

更新

C标准中,我找到了一个注释,上面写着

如果用于读取联合对象内容的成员与最后用于在对象中存储值的成员不同,则该值的对象表示形式的适当部分将被重新解释为新类型中的对象表示形式,如下所述6.2.6(有时称为类型双关的过程)。这可能是非值表示。

这意味着它在 C 中是允许的。但是,https://eel.is/c++draft/diff.iso

除了上面列出的差异之外,子条款 [diff.iso] 按本文档的章节列出了 C++ 和 ISO C 之间的差异。

没有指出差异。

Fed*_*dor 5

我认为在 C++ 中,根据问题本身的第一个标准引用,这是未定义的行为:对于相同类型的数据成员的情况也不例外。

主要编译器似乎同意这种解读,不允许在常量表达式中使用此类代码:

union A{
  int a;
  int b;
};

constexpr int f() {
  A u = {.a = 0};
  return u.b;
}

constexpr int x = f();
Run Code Online (Sandbox Code Playgroud)

在线演示: https: //gcc.godbolt.org/z/We4zYzdaa

铿锵的错误:

read of member 'b' of union with active member 'a' is not allowed in a constant expression
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会的错误:

accessing 'A::b' member instead of initialized 'A::a' member in constant expression
Run Code Online (Sandbox Code Playgroud)

MSVC 的错误:

failure was caused by accessing a non-active member of a union
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,所有编译器也拒绝非常相似但明确允许的 [\[class.mem.general\]/5](https://timsong-cpp.github.io/cppwp/n4868/class.mem.general# 25)。[演示](https://gcc.godbolt.org/z/von1seb4q)。 (2认同)