C语言中位字段与联合体的大小疑问及字节压缩需求
解答你的位字段与联合体大小疑问
先直接拆解你的两个问题,再给出压缩到8字节的方案:
1. 为什么结构体data_s的大小是10字节?
问题出在位字段的底层类型上:
- 你定义
uint64_t msg:48时,编译器会为这个位字段分配一个8字节(64位)的存储单元——因为位字段的存储单元大小由其底层类型决定,而非实际使用的位数。 - 接下来的
uint16_t crc:12,底层类型是uint16_t,编译器会再分配一个2字节(16位)的存储单元来存放这12位。 - 最后的
int:0是强制结束当前存储单元的布局,但这里已经用了两个独立的单元(8+2)。#pragma pack(push,1)和__attribute__((packed))只能消除结构体成员之间的填充字节,无法改变位字段底层类型带来的存储单元分配规则。所以总大小就是8+2=10字节。
2. 为什么联合体data_t的大小是16字节?
联合体的大小是其最大成员的大小,再向上对齐到当前平台下最大基本类型的对齐要求:
- 你的联合体成员中,
data_s是10字节,uint64_t是8字节,最大成员是10字节。 - 在大多数平台上,
uint64_t的对齐要求是8字节(即变量地址必须是8的倍数)。10字节需要向上对齐到最近的8的倍数,也就是16字节——这样才能保证联合体中的uint64_t成员始终处于对齐的地址上,避免未对齐访问的问题。
如何将位压缩到8字节中?
核心思路是让所有位字段共享同一个底层类型,这样编译器会把它们打包进同一个存储单元里。修改你的结构体定义,把所有位字段的底层类型统一为uint64_t:
#pragma pack(push, 1) typedef struct __attribute__((packed)){ uint64_t msg: 48; // 底层类型统一为uint64_t uint64_t crc: 12; // 同上 uint64_t : 4; // 可选:用匿名位字段填充剩下的4位,也可以省略 } data_s; #pragma pack(pop) typedef union { uint64_t tot; data_s split; } data_t;
修改后再运行,你会得到输出:Sizes are: union:8,struct:8,uint64_t:8。因为所有位字段都被放在同一个8字节的uint64_t单元里,结构体大小就是8字节;联合体的最大成员是8字节,对齐后还是8字节,完美符合你的需求。
内容的提问来源于stack exchange,提问作者Prateek Dhanuka
相关产品推荐
相关产品推荐

