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

含数组成员的联合数组中单个值的安全访问及malloc场景疑问

问题解答

先明确前提里的代码定义:

union Set {
    uint64_t z[2];
    uint32_t y[4];
    uint16_t x[8];
};

// 数组声明版本
union Set sets[SIZE] = { /* ... */ };

已知sets[1].x[0]是安全的访问方式,且联合无内存填充,下面分两种场景分析:

场景1:sets是声明的数组

从内存布局上看,每个union Set的大小是16字节(2个uint64_t,每个8字节),刚好对应8个uint16_t。sets[1]的起始地址相对于sets偏移16字节,而((uint16_t *)sets)[8]的偏移是8*2=16字节,两者的内存位置完全重合。

但从C标准的角度,这个操作存在未定义行为:

  • 严格别名规则规定,不同类型的指针不能用来访问彼此的对象(字符类型指针除外)。这里把union Set[]的指针强制转换成uint16_t*,然后访问第二个union Set的位置,属于违反严格别名规则的行为。
  • 编译器可能基于严格别名规则做优化,比如认定sets指向的是union Set类型数组,不会考虑uint16_t*类型的访问对它的影响,可能导致实际运行结果和预期不符(比如缓存的值被优化掉、地址计算出错)。

场景2:sets由malloc分配

如果sets是通过malloc分配的:

union Set *sets = malloc(SIZE * sizeof(union Set));

情况就不一样了:

  • malloc返回的是无类型内存块,直到你向其中存储数据,才会确定对应内存区域的有效类型。
  • 如果你已经通过sets[1].x[0]写入过数据,那么该内存位置的有效类型就是uint16_t,此时用((uint16_t *)sets)[8]访问是合法的,不存在未定义行为。
  • 如果还没对该位置做任何写入,直接读的话,问题出在读取未初始化内存本身是未定义行为,而非类型转换的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:33:20