You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将联合体首成员reinterpret_cast为活跃成员类型是否属于C++未定义行为?

结论

你给出的这段访问操作属于未定义行为,C++标准没有对该操作的行为做明确定义。

具体分析

首先我们先梳理代码中已确认合法的部分:

struct A { int i; };
struct B { std::string s; };

struct C
{
    union
    {
        A a{};
        B b;
    };
};

void foo()
{
    C c;        // 匿名联合体默认初始化,a是活跃成员,符合标准要求
    c.b = {};   // 对b的赋值操作自动将b切换为活跃成员,这一步本身合法
    // 问题出在下面这行代码
    auto& b = reinterpret_cast<B&>(c.a); 
}

问题出在reinterpret_cast<B&>(c.a)这行,主要有两个违反C++标准的点:

  • 违反严格别名规则:C++明确规定,对象的存储只能通过和对象类型兼容的左值访问,兼容类型包括和对象相同的类型、带const/volatile等限定的相似类型、char/unsigned char/std::byte三类字符类型。A和B是完全无关的自定义类型,不属于上述任意一种兼容范畴,直接将A类型的左值c.a转成B类型引用访问B对象,属于典型的别名违规。
  • 违反联合体成员访问规则:执行c.b = {}后联合体的活跃成员已经变为b,c.a是失效的非活跃成员,直接对非活跃成员做类型转换来访问另一个成员,不符合标准对联合体访问的约束。就算你明确知道联合体所有成员的起始地址相同,也不能直接这么操作,合法的跨成员地址转换必须基于联合体本身的指针/引用做转换,而不是基于非活跃成员的左值。

如果确实需要通过联合体的存储拿到当前活跃的b的引用,合法的写法如下(仅作语法合法演示,实际工程不推荐这种跨成员访问的写法):

auto& b = std::launder(reinterpret_cast<B&>(c));

这个写法基于联合体本身的左值做转换,符合C++20及之后版本的标准要求,是明确定义的。

内容的提问来源于stack exchange,提问作者Timo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 04:15:04