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

通过memcpy或std::bit_cast创建的union活跃成员及相关未定义行为问题

问题解答

先给出代码示例:

#include <stdint.h>
#include <string.h>
#include <bit>

union U
{
    uint64_t ull;
    int32_t i[2];
};

int main(int argc, char *argv[])
{
    uint64_t x = argc;
    U u;
    if (true)
        u = std::bit_cast<U>(x);
    else
        ::memcpy(&u, &x, sizeof(x));
    auto r = u.i[0];
    r += u.i[1];
    r += u.ull;
    return r;
}

1. auto r = ...行执行前,union u的活跃成员是哪个?

当if(true)分支执行时,std::bit_cast<U>(x)会创建一个存储内容与x完全一致的U对象。根据C++标准,通过std::bit_cast构造的union对象,活跃成员为声明顺序的第一个非静态数据成员ull——因为bit_cast仅按位完整复制内存,未显式初始化union的特定成员,此时默认以第一个成员作为活跃成员。

2. 代码中哪些行存在未定义行为,原因是什么?

  • auto r = u.i[0]; 和 r += u.i[1]; 存在未定义行为:
    当前union的活跃成员是ull,而i属于非活跃成员。C++标准仅允许在特定场景下读取非活跃成员(如读取unsigned char类型、或成员为标准布局且共享公共初始序列),但uint64_t与int32_t[2]既不属于unsigned char类型,也无符合要求的公共初始序列,因此读取i的行为属于未定义行为。
  • r += u.ull; 无未定义行为,因为读取的是当前活跃成员ull。
  • std::bit_cast的使用合法:U和uint64_t大小相同、均为标准布局类型,且对齐要求匹配,符合bit_cast的使用条件。

3. 将true改为false是否会改变上述问题的答案,若会,如何改变及原因是什么?

会改变部分答案:

  • 活跃成员变化:进入else分支后,u先被默认初始化(此时活跃成员为第一个成员ull,但未初始化),随后memcpy将x的内容复制到u的内存地址。memcpy仅修改内存字节,不会改变union的活跃成员,因此此时u的活跃成员依然是ull。
  • 未定义行为的变化:读取u.i[0]和u.i[1]依然是未定义行为,原因与之前一致——读取非活跃成员且不符合标准允许的例外场景。memcpy操作本身合法,它只是修改了活跃成员ull的内存内容,后续读取u.ull依然合法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:55:22