当前位置:嗨网首页>书籍在线阅读

19-位字段

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

15.4 位字段

操控位的第2种方法是位字段(bit field)。位字段是一个 signed intunsigned int 类型变量中的一组相邻的位(C99和C11新增了 _Bool 类型的位字段)。位字段通过一个结构声明来建立,该结构声明为每个字段提供标签,并确定该字段的宽度。例如,下面的声明建立了一个4个1位的字段:

struct {
     unsigned int autfd : 1;
     unsigned int bldfc : 1;
     unsigned int undln : 1;
     unsigned int itals : 1;
} prnt;

根据该声明, prnt 包含4个1位的字段。现在,可以通过普通的结构成员运算符( . )单独给这些字段赋值:

prnt.itals = 0;
prnt.undln = 1;

由于每个字段恰好为1位,所以只能为其赋值 10 。变量 prnt 被存储在 int 大小的内存单元中,但是在本例中只使用了其中的4位。

带有位字段的结构提供一种记录设置的方便途径。许多设置(如,字体的粗体或斜体)就是简单的二选一。例如,开或关、真或假。如果只需要使用1位,就不需要使用整个变量。内含位字段的结构允许在一个存储单元中存储多个设置。

有时,某些设置也有多个选择,因此需要多位来表示。这没问题,字段不限制1位大小。可以使用如下的代码:

struct {
     unsigned int code1 : 2;
     unsigned int code2 : 2;
     unsigned int code3 : 8;
} prcode;

以上代码创建了两个2位的字段和一个8位的字段。可以这样赋值:

prcode.code1 = 0;
prcode.code2 = 3;
prcode.code3 = 102;

但是,要确保所赋的值不超出字段可容纳的范围。

如果声明的总位数超过了一个 unsigned int 类型的大小会怎样?会用到下一个 unsigned int 类型的存储位置。一个字段不允许跨越两个 unsigned int 之间的边界。编译器会自动移动跨界的字段,保持 unsigned int 的边界对齐。一旦发生这种情况,第1个 unsigned int 中会留下一个未命名的“洞”。

可以用未命名的字段宽度“填充”未命名的“洞”。使用一个宽度为 0 的未命名字段迫使下一个字段与下一个整数对齐:

struct {
     unsigned int field1    : 1 ;
     unsigned int           : 2 ;
     unsigned int field2    : 1 ;
     unsigned int           : 0 ;
     unsigned int field3    : 1 ;
} stuff;

这里,在 stuff.field1stuff.field2 之间,有一个2位的空隙; stuff.field3 将存储在下一个 unsigned int 中。

字段存储在一个 int 中的顺序取决于机器。在有些机器上,存储的顺序是从左往右,而在另一些机器上,是从右往左。另外,不同的机器中两个字段边界的位置也有区别。由于这些原因,位字段通常都不容易移植。尽管如此,有些情况却要用到这种不可移植的特性。例如,以特定硬件设备所用的形式存储数据。