C语言中联合体内的结构体数组为何仅第一个元素值能被读取?
问题核心原因:C语言的结构体对齐与数组元素独立存储规则
你遇到的差异本质是数组元素的存储独立性要求和同结构体内位域的连续打包规则的区别,具体原因如下:
- 结构体数组的元素不会跨边界打包位域
C标准明确要求数组的每个元素都是可独立寻址的完整存储单元,相邻元素之间不能有内存重叠,也不能跨元素合并位域。
你定义的struct struct_v1虽然仅用了5位(2位a+3位b),但编译器会默认以unsigned int为单位处理位域存储,因此sizeof(struct struct_v1)多数场景下为4字节。数组的第二个、第三个struct struct_v1元素会分别从偏移4字节、8字节的位置开始存储,完全不在联合体里uint16_t覆盖的前2字节范围内,因此读取data_uint只能拿到第一个数组元素的值。 - 单结构体内的位域会连续打包
同一个结构体内部的相邻位域,只要剩余的存储空间足够容纳下一个位域,编译器就会将它们连续打包到同一个存储单元中。你定义的struct struct_v2总位宽为2+3+2+3+2+3=15位,刚好可以塞进2字节的uint16_t中,因此读取data_uint可以拿到所有位域的合并值。
验证方法
你可以在代码中加入一行打印,就能直观看到差异:
printf("sizeof(struct struct_v1) = %zu, 数组总大小 = %zu\n", sizeof(struct struct_v1), sizeof(union_v1.data));
打印结果会显示struct struct_v1的大小远大于5位,3个元素的总大小也远大于uint16_t的2字节,后续元素的存储位置根本不在data_uint的读取范围内。
解决方案
如果需要用数组式的逻辑访问位域又要合并到16位变量中,不能直接用结构体数组实现,可选方案:
- 用
struct_v2的方式把所有位域统一定义在同一个结构体中 - 手动封装宏/函数,通过位运算模拟数组下标访问位域
内容的提问来源于stack exchange,提问作者HennyKo
相关产品推荐
相关产品推荐

