将union指针直接转换为其数组成员元素类型指针的合法性探究
关于Union指针转换与访问的合法性分析
针对你提出的两个问题,结合C标准规则逐一解答:
1. 直接将union Obj64*转换为uint16_t*是否合法?
合法。
根据C标准规定:指向union对象的指针可以转换为指向其任意成员类型的指针,反之亦然。你的Obj64 union包含uint16_t u16[4]成员,指向数组类型的指针可隐式衰减为指向其元素类型的指针(uint16_t*)。同时:
- union对象的起始地址与所有成员的起始地址完全重合;
- 你的
static_assert保证了union无尾部填充,且uint64_t的对齐要求不低于uint16_t,转换后的uint16_t*满足对齐要求。
直接转换(uint16_t *)union_ptr等价于先将union指针转为指向uint16_t[4]的指针,再通过数组到指针的衰减得到uint16_t*,完全符合C标准的指针转换规则。
2. 两种方式获取的指针在未定义行为上的差异
两种指针的核心差异在于有效访问范围的定义:
- 通过
union_ptr->u16获取的指针,本质是指向u16数组对象的指针。该数组的有效索引范围是0~3,访问union_ptr->u16[4]属于数组越界访问,是明确的未定义行为——编译器可能进行激进优化、导致内存访问错误或其他不可预测的结果。 - 直接转换得到的
uint16_t*,指向的是union对象的起始内存。如果内存区域是连续的Obj64缓冲区,((uint16_t *)union_ptr)[4]本质是访问下一个Obj64对象的u16[0]成员。由于uint16_t是union的成员类型之一,根据strict aliasing规则,用uint16_t*访问union对象的内存合法;再加上static_assert保证每个union无填充,连续布局的union之间无额外内存间隙,因此该访问属于定义行为。
需注意,这种跨union访问仅在内存连续且无填充的前提下有效,若union存在未预期填充(已被断言排除),则会触发未定义行为。
内容的提问来源于stack exchange,提问作者CPlus
相关产品推荐
相关产品推荐

