C语言位域(位段)
应用场景
有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。
位域实例
结构体定义
struct bs{
unsigned int m;
unsigned int n: 4;
unsigned char ch: 6;
};
m:占用 4 个字节(Byte)的内存;
n:“:”后面的数字限定n占用的位数,不能再根据数据类型计算长度,n占用4位(Bit)内存;
ch:占用6位(Bit)内存。
#include <stdio.h>
int main(){
struct bs{
unsigned m;
unsigned n: 4;
unsigned char ch: 6;
} a = { 0xad, 0xE, '$'};
//第一次输出
printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
//更改值后再次输出
a.m = 0xb8901c;
a.n = 0x2d;
a.ch = 'z';
//第二次输出
printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
return 0;
}
运行结果:
0xad, 0xe, $
0xb8901c, 0xd, :
对于 n 和 ch,第一次输出的数据是完整的,第二次输出的数据是残缺的。
第一次输出:n、ch 的值分别是 0xE、0x24('$' 对应的 ASCII 码为 0x24),换算成二进制是 1110、10 0100,都没有超出限定的位数,能够正常输出。
第二次输出:n、ch 的值变为 0x2d、0x7a('z' 对应的 ASCII 码为 0x7a),换算成二进制分别是 10 1101、111 1010,都超出了限定的位数。超出部分被直接截去,剩下 1101、11 1010,换算成十六进制为 0xd、0x3a(0x3a 对应的字符是 :)。
C语言标准规定
1)位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,“:”后面的数字不能超过这个长度。
2)只有有限的几种数据类型可以用于位域。在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。
3)编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。
上一篇: RT-Thread的线程-rt_thread_init
下一篇: init vs clinit