Does reading to another variant member of a union that has the same type as the active variant cause UB?

huangapple go评论62阅读模式
英文:

Does reading to another variant member of a union that has the same type as the active variant cause UB?

问题

union A {
  int a;
  int b;
};
int main() {
  A u = {.a = 0};
  int r = u.b; // #1 这是否属于未定义行为?
}

[class.union] 规定:
> 在联合体中,如果非静态数据成员的名称引用的是已经开始但尚未结束生命周期的对象,则该成员是活跃的。在任何时候,联合体对象的一个非静态数据成员最多只能是活跃的,也就是说,在任何时候,最多只能在联合体中存储一个非静态数据成员的值。

在这个例子中,只有 A::a 是活跃的,然后[basic.life] 第7段规定:
> 如果程序使用 glvalue 来访问对象,或者

#1 试图访问尚未开始生命周期的对象。这种访问是否会导致未定义行为?如果是的话,这个要求是否太严格了?

另外,C 标准是否在这个例子中施加了相同的要求?还是说,C 在这种情况下有更宽松的要求?

更新

C标准中,我找到了一个注释,其中提到:
> 如果用于读取联合体对象的内容的成员与最后用于在对象中存储值的成员不同,则该值的对象表示的适当部分将被重新解释为新类型的对象表示,如6.2.6中所述(有时称为类型切换过程)。这可能是非值表示。

这意味着在C中是允许的。然而,https://eel.is/c++draft/diff.iso
> 子句 [diff.iso] 列出了C++和ISO C之间的差异,除了上面列出的差异外,还包括本文各章的差异。

并没有指出差异。

英文:
union A{
  int a;
  int b;
};
int main(){
  A u = {.a = 0};
  int r = u.b; // #1 Is this UB?
}

[class.union] says
> In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended ([basic.life]).
At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

In this example, only A::a is active, then [basic.life] p7 says
> The program has undefined behavior if:
>> - the glvalue is used to access the object, or

#1 tries to access the object whose lifetime has not begun. Does this access cause UB, if it is, is this requirement too restrictive?

BTW, Does the C standard impose the same requirement in this example? Or, Does C have a looser requirement in this case?

Update

In C standard, I find a note, which says
> If the member used to read the contents of a union object is not the same as the member last used to store a value in the
object the appropriate part of the object representation of the value is reinterpreted as an object representation in the new
type as described in 6.2.6 (a process sometimes called type punning). This might be a non-value representation.

This means it is permitted in C. However, https://eel.is/c++draft/diff.iso
> Subclause [diff.iso] lists the differences between C++ and ISO C, in addition to those listed above, by the chapters of this document.

does not point out the difference.

答案1

得分: 5

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

而且,主要的编译器似乎也支持这种解释,在常量表达式中禁止这样的代码:

union A{
  int a;
  int b;
};

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

constexpr int x = f();

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

Clang的错误:

尝试在常量表达式中读取联合体的成员'b',而成员'a'处于活动状态,不允许

GCC的错误:

在常量表达式中访问'A::b'成员,而不是已初始化的'A::a'成员

MSVC的错误:

访问联合体的非活动成员导致失败

(请注意,这是上述代码的翻译,不包括代码本身。)

英文:

I think in C++ this is undefined behavior per the first standard quotation in the question itself: there is no exception there for the case of same types of data members.

And major compilers seem to agree with this reading, disallowing such code in constant expressions:

union A{
  int a;
  int b;
};

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

constexpr int x = f();

Online demo: https://gcc.godbolt.org/z/We4zYzdaa

Clang's error:

read of member 'b' of union with active member 'a' is not allowed in a constant expression

GCC's error:

accessing 'A::b' member instead of initialized 'A::a' member in constant expression

MSVC's error:

failure was caused by accessing a non-active member of a union

答案2

得分: 3

> Does reading to another variant member of a union that has the same type as the active variant cause UB?

规则很清楚。一个成员是活动的。读取非活动成员会导致未定义行为。

> Does this access cause UB

是的。

> , if it is, is this requirement too restrictive?

不清楚。主观看法:对我来说没问题。这是可以接受的。我认为在联合体中有两个相同类型的成员,然后访问它们之一没有什么意义。

> Does the C standard impose the same requirement in this example?

不。这是C和C++不同的例子之一。

> Does C have a looser requirement in this case?

是的。在C中,你可以读取联合体中的任何成员。要求的是评估的值不会是 trap representation。

相关链接:https://stackoverflow.com/questions/25664848/unions-and-type-punning

英文:

> Does reading to another variant member of a union that has the same type as the active variant cause UB?

The rule is clear. One member is active. Reading inactive is UB.

> Does this access cause UB

Yes.

> , if it is, is this requirement too restrictive?

No idea. Subjective: Not for me. It is fine. I see no value in having two members of the same type in a union and then accessing them one or the other.

> Does the C standard impose the same requirement in this example?

No. One of examples that C and C++ are different.

> Does C have a looser requirement in this case?

Yes. In C, you can read any member from a union you want to. The requirement is that the assessed value will not be a trap representation.

Related: https://stackoverflow.com/questions/25664848/unions-and-type-punning

huangapple
  • 本文由 发表于 2023年5月24日 20:21:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76323477.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定