访问不活动的联合成员和未定义的行为? [英] Accessing inactive union member and undefined behavior?

查看:270
本文介绍了访问不活动的联合成员和未定义的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的印象是,访问联合成员而不是最后一个是UB,但我似乎找不到一个坚实的参考(除了答案

I was under the impression that accessing an union member other than the last one set is UB, but I can't seem to find a solid reference (other than answers claiming it's UB but without any support from the standard).

因此,它是未定义的行为吗?

So, is it undefined behavior?

推荐答案

混淆是C明确允许通过联合类型冲突,而C ++( c ++ 11 )没有这样的权限。

The confusion is that C explicitly permits type-punning through a union, whereas C++ (c++11) has no such permission.


c11 的问题

95)如果用于读取union对象的内容的成员不同于最后用于
的成员在对象中存储一个值,该值的对象表示的适当部分被重新解释为
作为新类型中的对象表示,如第6.2.6节所述(有时称为''type
punning'')。这可能是一个陷阱表示。

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 ++的情况:

c ++ 11

非静态数据成员之一可以在任何时间是活动的,也就是说,
的值可以将非静态数据成员中的大多数成员随时存储在并集中。

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 ++稍后有允许使用包含通用初始序列的 struct

C++ later has language permitting the use of unions containing structs with common initial sequences; this doesn't however permit type-punning.

要确定C ++中是否允许联合类型冲突,我们必须进一步搜索。回想一下, c99 是C ++的规范性参考11(和C99与C11具有类似语言,允许联合类型冲突):

To determine whether union type-punning is allowed in C++, we have to search further. Recall that c99 is a normative reference for C++11 (and C99 has similar language to C11 permitting union type-punning):


3.9类型[basic.types]



4 - 类型T的对象的对象表示是由
占用的N个unsigned char对象的序列,类型T的对象,其中N等于sizeof(T)。对象的值表示是
保存类型T的值的一组位。对于简单可复制类型,值表示是对象
表示中的一组位,其确定值,是
值的实现定义集合的一个离散元素。 42

42)目的是C ++的内存模型与ISO / IEC 9899编程语言C的内存模型兼容。

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.

当我们阅读

类型T的对象的生命周期开始于:
- 获取类型T的正确对齐和大小的存储,
- 如果对象有非平凡的初始化,它的初始化就完成了。

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.

/ em>包含在联合体中,对象的生命周期至少包含联合体自身的生命周期。这允许我们调用

So for a primitive type (which ipso facto has trivial initialization) contained in a union, the lifetime of the object encompasses at least the lifetime of the union itself. This allows us to invoke


3.9.2复合类型[basic.compound]



如果类型T的对象位于地址A,则值为
地址A的类型cv T *的指针被称为指向该对象,而不管如何获得该值。 p>

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.

假设我们感兴趣的操作是类型划分,即取非活动联合成员的值,我们有一个对该成员引用的对象的有效引用,该操作是左值到右值转换:

Assuming that the operation we are interested in is type-punning i.e. taking the value of a non-active union member, and given per the above that we have a valid reference to the object referred to by that member, that operation is lvalue-to-rvalue conversion:


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



一个非函数非数组类型的glvalue T 可以转换为prvalue。
如果 T 是不完整类型,则需要此转换的程序是错误的。 如果glvalue引用的对象不是类型 T 的对象,并且不是从 T code>,或者如果对象未初始化,则需要此转换的程序具有未定义的行为。

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.

然后,问题是作为非活动联合成员的对象是否通过存储初始化到活动联合成员。据我所知,情况不是这样,虽然如果:

The question then is whether an object that is a non-active union member is initialized by storage to the active union member. As far as I can tell, this is not the case and so although if:


  • 一个联合被复制到 char 数组存储并返回(3.9:2)或

  • 将并集同位复制到同一类型的另一个union(3.9:3) / li>
  • 通过符合ISO / IEC 9899(至定义)的程序元素跨语言边界访问并集(3.9:4注释42),则

  • a union is copied into char array storage and back (3.9:2), or
  • a union is bytewise copied to another union of the same type (3.9:3), or
  • a union is accessed across language boundaries by a program element conforming to ISO/IEC 9899 (so far as that is defined) (3.9:4 note 42), then

定义了非活动成员对并集的访问,并定义为遵循对象和值表示,上述插值之一是未定义的行为。这对于允许在这样的程序上执行的优化具有影响,因为实现当然可以假定不会发生未定义的行为。

the access to a union by a non-active member is defined and is defined to follow the object and value representation, access without one of the above interpositions is undefined behaviour. This has implications for the optimisations allowed to be performed on such a program, as the implementation may of course assume that undefined behaviour does not occur.

也就是说,尽管我们可以合法地形成对非活动联盟成员的左值(这就是为什么分配给没有构造的非活动成员是确定的),它被认为是未初始化的。

That is, although we can legitimately form an lvalue to a non-active union member (which is why assigning to a non-active member without construction is ok) it is considered to be uninitialized.

这篇关于访问不活动的联合成员和未定义的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆