采用以下代码
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/