C 位域
位域是操控位的一种方法
有些数据在存储时只占用一个或几个二进制位,并不需要占用一个完整的字节。基于这种考虑,C语言又提供了一种数据结构,叫做“位域”或“位段”。
位域通过一个结构声明来建立:该结构声明为每个字段提供标签,并确定该字段的宽度。例如,下面的声明建立了个4个1位的字段:
struct
{
unsigned int autfd:1;
unsigned int bldfc:1;
unsigned int undin:1;
unsigned int itals:1;
}prnt;
根据该声明, prnt包含4个1位的字段。现在,可以通过普通的结构成员运算符(.)单独给这些字段赋值:
prnt.itals = 0:
prnt.undin = 1;
由于每个字段恰好为1位,所以只能为其赋值1或0。变量prnt被储存在int大小的内存单元中
:后面的数字用来限定成员变量占用的位数。位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。
如上述结构中autfd、bldfc、undin、itals后面的数字不能超过unsigned int的位数,即在32bit环境中就是不能超过32。
位域的取值范围非常有限,数据稍微大些就会发生溢出,请看下面的例子:
#include <stdio.h>
struct pack
{
unsigned a:2; // 取值范围为:0~3
unsigned b:4; // 取值范围为:0~15
unsigned c:6; // 取值范围为:0~63
};
int main(void)
{
struct pack pk1;
struct pack pk2;
// 给pk1各成员赋值并打印输出
pk1.a = 1;
pk1.b = 10;
pk1.c = 50;
printf("%d, %d, %d\n", pk1.a, pk1.b, pk1.c);
// 给pk2各成员赋值并打印输出
pk2.a = 5;
pk2.b = 20;
pk2.c = 66;
printf("%d, %d, %d\n", pk2.a, pk2.b, pk2.c);
return 0;
}
程序输出结果为:
pk1.a = 1, pk1.a = 10, pk1.c = 5
pk2.a = 1, pk2.b = 4, pk2.c = 2
位域声明
在结构内声明位域的形式如下:
struct
{
type [member_name] : width ;
};
下面是有关位域中变量元素的描述:
元素 |
描述 |
type |
整数类型,决定了如何解释位域的值。类型可以是整型、有符号整型、无符号整型。 |
member_name |
位域名 |
width |
位域中位的数量。宽度必须小于或等于指定类型的位宽度。 |
带有预定义宽度的变量被称为位域。位域可以存储多于 1 位的数,例如,需要一个变量来存储从 0 到 7 的值,您可以定义一个宽度为 3 位的位域,如下:
struct
{
unsigned int age : 3;
} Age;
上面的结构定义指示 C 编译器,age 变量将只使用 3 位来存储这个值,如果您试图使用超过 3 位,则无法完成。让我们来看下面的实例:
#include <stdio.h>
#include <string.h>
struct
{
unsigned int age : 3;
} Age;
int main( ) {
Age.age = 4;
printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
printf( "Age.age : %d\n", Age.age );
Age.age = 7;
printf( "Age.age : %d\n", Age.age );
Age.age = 8;
printf( "Age.age : %d\n", Age.age );
return 0;
}
尝试一下
当上面的代码被编译时,它会带有警告,当上面的代码被执行时,它会产生下列结果:
Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0