先来一篇C语言位域的好文:C语言位域(位段)详解
当我们不需要使用一个完整的字节时,我们会使用位域。
常见的位域使用方法如下
typedef struct {
unsigned a:8;
unsigned b:16;
char c:8;
}A;
当然我们也可以结合联合体一起使用,可以更方便对位域整体进行赋值
typedef union {
unsigned int d;
struct {
unsigned a:8;
unsigned b:16;
char c:8;
}bitField;
}A;
这种使用方法,我们只需要对d进行赋值,就可以同时对位域内所有元素进行赋值。
下面我们测试一下在位域中是否可以显示有符号数
#include <stdio.h>
typedef union {
unsigned int d;
struct {
unsigned a:8;
unsigned b:16;
char c:8;
}bitField;
}A;
int main(){
A test;
test.bitField.a = 0xff;
test.bitField.c = 0xff;
printf("%d\n",test.bitField.a);
printf("%d\n",test.bitField.c);
return 0;
}
可以看到对于unsigned无符号数将二进制表示11111111解释成了255
对于char有符号数将二进制表示11111111解释成了-1
因此在位域中是可以使用有符号数的,只要我们对该元素进行有符号数的声明即可。
现在我们知道在位域中可以定义各种类型的整型元素,包括char|unsigned char|int|unsigned int等,但是要注意的是,当你将一个元素声明为unsigned char之后,如果该元素的内存占用不足8位的话,那是达不到unsigned char的[0,255]范围。
#include <stdio.h>
typedef union {
unsigned int d;//int d也可以
struct {
unsigned char a:7;
unsigned b:17;
char c:8;
}bitField;
}A;
int main(){
A test;
test.bitField.a = 0xff;
printf("%d\n",test.bitField.a);
return 0;
}
可以看到我们将a元素声明为unsigned char类型,但是其只占7比特,当我们把0xff(二进制表示11111111)赋值给a,a因为内存不够,会发生高位截断,因此a的二进制表示为1111111,其十进制值是127
下面我们试试当我们定义的元素位数大于整型类型的位数时,会咋样?
#include <stdio.h>
typedef union {
int d;
struct {
unsigned char a:9;
unsigned b:16;
char c:8;
}bitField;
}A;
int main(){
A test;
test.bitField.a = 0x1ff;//十进制511,二进制111111111
printf("%d\n",test.bitField.a);
return 0;
}
可以看到我们传入了一个9比特能够容纳的最大值(二进制表示为111111111),但是因为unsigned char只占用8位,因此其只能解释8位的数据,即(11111111),故打印结果是255
总结
-
unsigned和unsigned int是等价的
-
当我们要使用位域时,要了解好我们是使用无符号数还是有符号数
-
当我们使用位域中的元素时,其内存占用位数可能不是正好等于8、16、32,这样我么在选择整型类型时,要有一定余度。即<=8位的选择char,<=16位的选择short,<=32位的选择int,至于大于32位的,我们很少使用,因为位域就是主要针对不到一个字节的使用。