使用联合时未定义行为的情况

Dev*_*Dev 2 c++ undefined-behavior

我有以下代码来自“C++17 详解”一书:

union Superfloat{
float f;
int i;
}

int RawMantissa(Superfloat f){
return f.i & ((1< 23) -1);
}

int RawExponent(Superfloat f){
return (f.i >> 23)& 0xFF;
}

Run Code Online (Sandbox Code Playgroud)

在那段代码之后,Bartlomiej Filipek 先生写道:“然而,虽然上面的代码可能在 C99 中工作,但由于更严格的别名规则,它在 C++ 中是未定义的行为”。

我想更好地理解作者这句话的意思,因为我不明白。你能详细给我解释一下吗?

他给出了以下解释(但我需要更多解释):

C.183!...读取与写入时类型不同的联合成员是未定义的。这种双关语是不可见的,或者至少比使用命名的 >cast 更难发现.....

我也不明白这个解释,以及它如何帮助理解上面的代码是未定义的行为。

我将感谢您的深入解释

bol*_*lov 5

这很简单。一个工会至多有一名成员活跃。当您写入成员时,该成员将变为活动状态。您只能从活动成员中读取。

例子:

union U
{
    float f;
    int i;
};

auto foo_1()
{
    U u; // no member is active

    u.f = 24.5; // write to `u.f` . `u.f` is now the active member

    int i = u.i; // read of `u.i` Since `u.i` is not the active member this is UB in C++
}
Run Code Online (Sandbox Code Playgroud)
auto foo_2()
{
    U u;
    // no active member

    u.f = 24.5; // write to `u.f` . `u.f` is now the active member

    float f = u.f; // read of `u.f` . Ok since `u.f` is the active member

    u.i = 11; // write to `u.i` . `u.i` is now the active member.
              // `u.f` is NOT the active member anymore

    int i = u.i; // ok, read of the active member `u.i`

    float f2 = u.f; // read of `u.f`. UB, since `u.f` is not the active member
}
Run Code Online (Sandbox Code Playgroud)

  • @walnut 我不明白这如何排除你的情况。我们简单地陷入第三种情况/项目符号 - _S(e)_ 为空,如果您的左侧操作数只是一个名称“nameOfReferenceToUnionMember”,则确实如此。您能否详细说明为什么您认为该部分通过引用工会成员排除了分配? (2认同)
  • @LightnessRaceswithMonica 第一句要求成员访问运算符出现在赋值的左侧,如果集合为空,则“*对于 S(E1) 的每个元素 X,[...] 的对象X 的类型是在指定存储中隐式创建的*”不会创建任何对象,因此不会更改任何活动成员。(这是我读到的。) (2认同)