分配后工会的活跃成员

Active member of an union after assignment

提问人:cerveka2 提问时间:8/31/2022 最后编辑:timraucerveka2 更新时间:9/19/2022 访问量:466

问:

假设 ,我有以下代码片段:sizeof( int ) == sizeof( float )

union U{
    int i;
    float f;
};

U u1, u2;
u1.i = 1;    //i is the active member of u1
u2.f = 1.0f; //f is the active member of u2

u1 = u2;

我的问题:

  1. 它有明确的行为吗?如果不是,为什么?
  2. 分配后的活跃成员是什么,为什么?u1
  3. 分配后可以从哪个成员中读取而不会引起 UB,为什么?u1
C++ 未定义行为 联合赋 值运算符

评论

4赞 Jeffrey 8/31/2022
当然是这部分。执行分配时,活动成员将与其他成员一起复制。但我会让精通标准答案的人。float
0赞 chi 8/31/2022
我认为这不应该是UB,即使大小不相等。分配应使具有与 相同的活动成员。u1 = u2;u1u2
2赞 qwr 9/1/2022
这个标题听起来像是一个 Workplace SE 问题!

答:

13赞 AProgrammer 8/31/2022 #1
  1. 它有明确的行为吗?如果不是,为什么?

它定义了行为。分配副本的值,对我来说,联合的值是活动成员的指定(尽管该部分没有表示,因此无法检查,但它决定了什么是 UB,什么不是)和活动成员的值(如果有的话)。u2

  1. 分配后 u1 的活跃成员是什么,为什么?

f,见上文。

分配后可以从哪个 u1 成员中读取而不会引起 UB,为什么?

f.通常,在 C++ 中,只有没有 UB 的情况下才能读取联合的活动成员。结构的并集有一个特殊的规则,其中这些结构具有共同的初始序列。注意:C更宽松,并且定义了实现(也许完全定义)了一些在C++中未定义的情况,我可能错过了C++中的一些更改,以使其与C更兼容。


如果有人想查找标准,我建议从 class.copy.assign/13 开始。

评论

0赞 H.S. 8/31/2022
从第一点开始,与为 和 类型赋值相同。它是否适用于所有情况(无论价值如何)?u1 = u2floatintu2.f
0赞 AProgrammer 8/31/2022
我的理解(我没有时间用标准引用来支持,我对那个游戏很生疏,不得不重新发现我曾经知道的东西),是结束 , 一个类型的对象的生存时间,开始 , 同一地址的类型对象的生存期,分配给该对象。只要有效,分配就有效。u1 = u2u1.iintu1.ffloatu2.fu2.f
2赞 Peter Cordes 9/1/2022
请注意,许多 C++ 实现确实定义了读取非活动联合成员的行为。例如,所有实现 C 和 C++ 的 GNU 扩展的编译器,如 GCC、clang 和 ICC,都像 C99 一样定义它。ISO C++ 未定义行为并不会阻止实现定义它。GCC 引用 C89/C90 标准来描述它的方式似乎确实表明 C89 需要实现来选择某些行为,但这是古老的;现代 C 语言定义了它
1赞 Peter Cordes 9/1/2022
(“实施定义的行为”具有特定的含义,即 ISO 标准要求实施以某种方式定义的行为。我不记得 C89 定义了联合类型双关语实现,这是一个非常晦涩难懂的观点,所以我只是想为未来的读者做出这种区分。C99 及更高版本完全定义了该行为。许多但不是全部的现代C++编译器也定义了行为,但ISO C++没有。所以+1)
0赞 supercat 9/2/2022
@PeterCordes:查看 C89 缺陷报告 #028,我认为没有明确说明“实现定义”应该意味着什么。在考虑类似 : 时,缺陷报告 #028 指出,由于行为或写入一个成员并读取另一个成员是实现定义的,因此不允许执行此类操作,因此通过指针执行此类操作将产生未定义的行为。只有当IDB和UB接近同义词时,这种说法才有意义。int test(void) { union U { float f; int i; } u; int *fp = &u.f; *fp = 1.0; int *ip = &u.i; return *ip; };