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

为何将union成员指针转为union指针并非UB?二者大小不同

C++联合体与指针强制转换的内存合法性问题

问题代码

class A {
public:
  int x;
  A() {
    x = 5;
  }
};

class B {
public:
  int x;
  float y;
  B() {
    x = 10;
    y = 3.14;
  }
};

union U {
  A a;
  B b;
};

U* foo(U* u) {
  B* b = new B();
  u->b = *b;
  return u;
}

int main() {
  A* a  = new A();
  U* u = (U*) a;
  u = foo(u);
  return u->b.y;
}

核心疑问

这段代码执行u->b = *b;时会出现缓冲区溢出。查阅资料得知(U*)a这类转换应为良定义,但因sizeof(U) != sizeof(A)对此存疑;同时不确定U与A是否为指针可互转(pointer-interconvertible)类型,以及这是否意味着转换合法,难以理解相关C++标准。

问题解答

  1. 指针转换的合法性判定
    C++标准中,只有两个类型属于指针可互转类型时,这类强制转换(C风格转换等价于reinterpret_cast)才是良定义的。指针可互转的场景包括:

    • 同一类型的对象指针
    • 标准布局类型的非静态数据成员指针与所属对象指针
    • 标准布局联合体的成员指针与所属联合体对象指针

    但这里的情况完全不符合:A对象是单独new出来的,并非联合体U的成员,所以A*转U*不属于合法的指针互转场景,本质是未定义行为。

  2. sizeof不匹配直接导致溢出
    联合体的大小由其最大成员决定,sizeof(U)等于sizeof(B)(假设int为4字节、float为4字节,总大小8字节),而sizeof(A)仅为4字节。将仅分配了4字节内存的A对象强制转为U*后,访问并写入U::b(需要8字节内存)必然会越界,这就是缓冲区溢出的直接原因。

  3. 对“转换良定义”的误区
    部分资料提到的合法转换,指的是当联合体对象的活跃成员是某一成员时,该成员指针与联合体指针可安全互转(比如拥有一个U对象且活跃成员是a,此时U*和A*可互转)。但单独的A对象并非U的成员,完全不适用这个规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:35:59