c++ - 与标准布局结构 union 中的未定义行为

标签 c++ language-lawyer undefined-behavior constexpr unions

采用以下代码

union vec
{
    struct
    {
        float x, y, z;
    };

    float data[3];

    constexpr vec() : data{} {}
};

constexpr vec make_vec(float x, float y, float z)
{
    vec res;
    res.data[0] = x;
    res.data[1] = y;
    res.z = z;
    return res;
}

int main()
{
    constexpr vec out = make_vec(0, 1, 2);
    std::cout << out.z << '\n';
}

这里我使用constexpr来判断代码是否为未定义行为,因为未定义行为会导致编译错误。

§9.2/19:

If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them.

据此,我假设代码中的所有内容都将被定义为行为。

使用 g++ main.cpp -o out -std=c++17 进行编译,我收到消息 error: change of the active member of a union from 'vec::data' to 'vec::<anonymous>' .

我认为为了符合标准,我可能不得不将其更改为这样--

union vec
{
    struct
    {
        float x, y, z;
    };

    struct
    {
        float data[3];
    };

    constexpr vec() : data{} {}
};

但我遇到了同样的错误。

这真的是未定义的行为吗?我是否错过了该标准的另一部分,或者我只是误解了该标准?

最佳答案

是的,这是UB。

写入 union 体的 float data[3]; 部分后,您将无法读取 struct { float x, y, z; };

就这么简单。

that share a common initial sequence

不涵盖这两个,因为数组与一个 float 后跟另一个 float 不同。

重要修改

上面的答案假设代码是 UB,因为 .x.y 成员无效。正如@user17732522 指出的那样。它比这更微妙。

.x.y 返回时未初始化,并且具有未定义的值。但是对 .z 成员的写入确实设置了 union 的事件成员。因此,只要调用代码仅读取 .z 成员,所有内容都已定义且正确。

关于c++ - 与标准布局结构 union 中的未定义行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74104268/

相关文章:

c++ - 冒泡排序中赋值 c++ 的左操作数需要左值

c++ - 类型类方法的参数推导(由 const 限定符重载)在 gcc 中以尾随返回类型失败,但在 clang 中没有

c - 没有返回类型的 C 函数的未定义行为

c++ - 随机循环终止条件是否明确定义?

c++ - 在静态成员变量初始值设定项中,为什么调用静态成员函数(不是全局函数)?

c# - 带有非传递 IComparer 的 OrderBy

c++ - 通过 HLSL C++ 时常量缓冲区为空

c++ - 错误 : Illegal zero sized array

c++ - C 编译 : error: stray '\4' in program ; octal flow?

c++ - 作为非类型模板参数的引用