1.位域的定义
C语言中位域也叫位段,经常在STM32或DSP固件库中应用。ANSI C标准中规定,有下面三种数据类型可以用于位域,signed int 和 unsigned int 和_Bool。
struct
{
unsigned int a:1;
unsigned int b:2;
unsigned int c:1;
}abc;
上面声明建立了2个1位的字段,1个2位的字段。abc.a或c可以赋值为0或1,而abc.b可以赋值为0~3,因为它占两位。:冒号后面的数字用来限定成员变量占用的位数。
2. 位域的宽度
位域宽度不能超过它所依附的数据类型长度,比如上面冒号后面数字不能超过int占用位数,32位环境中int占32位,所以上述声明冒号后面数字都不能超过32.
3. 位域的存储
上述例子中结构体只占用4个字节(考虑对齐),假如下面的声明:
struct
{
unsigned int a:2;
unsigned int b:1;
unsigned int c:31;
}abc;
上述声明abc.c占用31位,abc.b占用1,abc.a占用2位,但是结构体总共占用8个字节空间。其中abc.a占用前面4个字节,abc.c和b占用后面4个字节,如有描述错误,欢迎指正~~~
4. 无名位域
struct
{
unsigned int a:2 ;
unsigned int :18 ;
unsigned int c:16;
}abc;
上面声明中,如果没有位宽为18的无名成员,a和c将挨着存储共占用4个字节。有了18的无名成员作为填充,a和c将分开存储,结构体占8个字节,前4个字节存a和无名成员,后四个字节存c,无名成员不能使用。所以无名位域主要用于调整成员存储位置或填充内存。
5. 位的应用
下面是某MCU固件库对寄存器的封装,所有寄存器都被封装为联合体类型,联合体里面有一个32位的成员和一个结构,该结构以位域的形式体现,这样操作某些寄存器的位就比较方便了。
unon GPIOA_REG uGPIOAREG;
比如要操作GPIOA的bit4-7位为0101,uGPIOAREG.bit.GPIO1=5即可,如果要把整个寄存器写1,只需要操作uGPIOAREG.all = 0xffff;即可。
除开上面应用外,还可以使用联合体结合位域的方式管理一些状态量,如果一个程序中有很多状态量要管理的话。