C语言位域的用法(附带实例)
位域(又叫位段)是一种特殊的结构体类型,其所有成员的长度均以二进制位为单位进行定义,结构体中的成员被称为位域。
C语言中,位域的一般定义形式如下:
一个位域必须是 int、unsigned 或 signed 中的一种。例如,CPU 的状态寄存器按位域类型定义如下:
显然,对 CPU 的状态寄存器而言,使用位域类型仅需 1 个字节即可。又如:

图 1 占位情况
1) 位域类型和位域变量的定义,以及位域成员的引用,均与结构体类型和结构体变量相同。
2) 在下面定义的位域结构中,各位域都只占用一个二进制位:
如果某位域需要表示多于两种状态,也可将该位域设置为占用多个二进制位。例如,字体大小有 4 种状态,则可将上面的位域结构改写成如下形式:
3) 某一位域要从另一个字节开始存放,可写成如下形式:
4) 可以使各位域占满一个字节,也可以不占满一个字节。例如:

图 2 不占满一个字节的情况
5) 一个位域必须存储在一个存储单元(通常为 1 字节)中,不能跨两个存储单元。如果本单元不够容纳某位域,则从下一个单元开始存储该位域。
6) 可以用“%d”、“%x”、“%u”、“%o”等格式字符,以整数形式输出位域。
7) 在数值表达式中引用位域时,系统自动将位域转换为整型数。
C语言中,位域的一般定义形式如下:
struct 结构体名 { 类型 变量名1:长度; 类型 变量名2:长度; … 类型 变量名n:长度; }
一个位域必须是 int、unsigned 或 signed 中的一种。例如,CPU 的状态寄存器按位域类型定义如下:
struct status { unsigned sign:1; /*符号标志*/ unsigned zero:1; /*零标志*/ unsigned carry:1; /*进位标志*/ unsigned parity:1; /*奇偶溢出标志*/ unsigned half_carry:1; /*半进位标志*/ unsigned negative:1; /*减标志*/ } flags;
显然,对 CPU 的状态寄存器而言,使用位域类型仅需 1 个字节即可。又如:
struct packed_data { unsigned a:2; unsigned b:1; unsigned c:1; unsigned d:2; }data;可以发现,这里 a、b、c、d 分别占 2 位、1 位、1 位、2 位,如下图所示。

图 1 占位情况
C语言位域的说明
前面介绍了什么是位域,这里针对位域的应用,有以下几点说明:1) 位域类型和位域变量的定义,以及位域成员的引用,均与结构体类型和结构体变量相同。
2) 在下面定义的位域结构中,各位域都只占用一个二进制位:
struct attribute { unsigned font:1; unsigned color:1; unsigned size:1; unsigned dir:1; };
如果某位域需要表示多于两种状态,也可将该位域设置为占用多个二进制位。例如,字体大小有 4 种状态,则可将上面的位域结构改写成如下形式:
struct attribute { unsigned font:1; unsigned color:1; unsigned size:2; unsigned dir:1; };
3) 某一位域要从另一个字节开始存放,可写成如下形式:
struct status { unsigned a:1; unsigned b:1; unsigned c:1; unsigned :0; unsigned d:1; unsigned e:1; unsigned f:1; }flags;原本 a、b、c、d、e、f 这 6 个位域是连续存储在一个字节中的。由于加入了一个长度为 0 的无名位域,因此其后的 3 个位域从下一个字节开始存储,一共占用两个字节。
4) 可以使各位域占满一个字节,也可以不占满一个字节。例如:
struct packed_data { unsigned a:2; unsigned b:2; unsigned c:1; int i; }data;存储形式如下图所示:

图 2 不占满一个字节的情况
5) 一个位域必须存储在一个存储单元(通常为 1 字节)中,不能跨两个存储单元。如果本单元不够容纳某位域,则从下一个单元开始存储该位域。
6) 可以用“%d”、“%x”、“%u”、“%o”等格式字符,以整数形式输出位域。
7) 在数值表达式中引用位域时,系统自动将位域转换为整型数。