gpt4 book ai didi

c++ - 访问不活跃的 union 成员和未定义的行为?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:44:47 25 4
gpt4 key购买 nike

我的印象是访问除最后一组以外的 union 成员是 UB,但我似乎找不到可靠的引用(除了声称它是 UB 但没有任何标准的支持)。

那么,这是未定义的行为吗?

最佳答案

令人困惑的是 C 明确允许通过 union 进行类型双关,而 C++ ( ) 没有这样的许可。

6.5.2.3 Structure and union members

95) 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 trap representation.

C++的情况:

9.5 Unions [class.union]

In a union, at most one of the non-static data members 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.

C++ 后来的语言允许使用包含具有公共(public)初始序列的 struct 的 union ;然而,这不允许类型双关。

要确定 C++ 中是否允许 union 类型双关,我们必须进一步搜索。回想一下 是 C++11 的规范性引用(并且 C99 具有与 C11 类似的语言,允许 union 类型双关):

3.9 Types [basic.types]

4 - The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T. For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values. 42
42) The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.

阅读时特别有趣

3.8 Object lifetime [basic.life]

The lifetime of an object of type T begins when: — storage with the proper alignment and size for type T is obtained, and — if the object has non-trivial initialization, its initialization is complete.

因此对于 union 中包含的基本类型(ipso facto 具有简单的初始化),对象的生命周期至少包含 union 本身的生命周期。这允许我们调用

3.9.2 Compound types [basic.compound]

If an object of type T is located at an address A, a pointer of type cv T* whose value is the address A is said to point to that object, regardless of how the value was obtained.

假设我们感兴趣的操作是类型双关,即获取一个非事件 union 成员的值,并且根据上面给出的我们有一个对该成员引用的对象的有效引用,该操作是左值到右值的转换:

4.1 Lvalue-to-rvalue conversion [conv.lval]

A glvalue of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

接下来的问题是,一个作为非事件 union 成员的对象是否通过存储初始化为事件 union 成员。据我所知,情况并非如此,尽管如果:

  • 将 union 复制到 char 数组存储并返回 (3.9:2),或者
  • 一个 union 按字节复制到另一个相同类型的 union (3.9:3),或者
  • union 由符合 ISO/IEC 9899 的程序元素跨语言边界访问(就定义而言)(3.9:4 注释 42),然后

非事件成员对 union 的访问已定义并定义为遵循对象和值表示,没有上述任何一种干预的访问是未定义的行为。这对允许在此类程序上执行的优化有影响,因为实现当然可以假设未定义的行为不会发生。

也就是说,虽然我们可以合法地为一个非活跃的 union 成员形成一个左值(这就是为什么在没有构造的情况下分配给一个非活跃成员是可以的)它被认为是未初始化的。

关于c++ - 访问不活跃的 union 成员和未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41128215/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com