6月1日 14:44
C语言位域(bit-field)有什么用?和位运算比哪个好?
位域(bit-field)让你在结构体里按位定义成员,指定每个成员占几个二进制位。主要用途是压缩存储——当多个标志位只需要 0/1 时,用位域把多个 bool 塞进一个 int 里,省内存。在网络协议解析和硬件寄存器映射中非常常见。
追问
位域怎么定义?占多少内存?
cstruct Flags { unsigned int read : 1; // 1 bit unsigned int write : 1; // 1 bit unsigned int execute : 1; // 1 bit unsigned int reserved: 29; // 填满 32 bit }; // sizeof(struct Flags) = 4 字节
冒号后面的数字是位宽。所有位域成员加起来不能超过底层类型的总位数(unsigned int 是 32 位)。如果超过,编译器会分配下一个存储单元。
位域有什么限制?
三个硬限制:1) 不能取地址——&flags.read 编译报错,因为位域没有独立的字节地址;2) 不能用指针指向位域成员;3) 赋值超出范围会截断——3 位位域最大值是 7,赋值 10 实际存的是 2(10 % 8)。
位域跨平台有什么坑?
大端序和小端序机器上,位域的排列方向可能相反——同样是 a:4, b:4,x86 上 a 在低 4 位,PowerPC 上 a 可能在高 4 位。另外不同编译器对位域的对齐和填充规则不同。所以位域不适合做跨平台的数据传输格式,只适合同一平台内部使用。网络协议解析用位域的话,要做字节序转换。
无名位域是干什么用的?
两个用途:unsigned :0 强制下一个位域从新的存储单元开始(对齐);unsigned :N(N>0)跳过 N 位不用(保留位)。协议头里经常用无名位域来对齐字段位置。
cstruct IPHeader { unsigned int version : 4; unsigned int ihl : 4; unsigned int tos : 8; unsigned int tot_len : 16; };
位域和位运算比哪个好?
位运算(flags |= 1 << 3)完全可控、跨平台、可移植,但可读性差。位域可读性好(flags.read = 1),但牺牲了可控性和可移植性。在嵌入式开发中,寄存器映射用位域更直观;跨平台代码用位运算更安全。实际项目里两种都有人用,看对可移植性的要求。