1.定义
计算机在处理有符号数时,通过其最高位来标识当前数的正负。但是在逻辑表达式及其运算中,真与假是通过一个16位整数来描述的,其中有15位的二进制数位的空间因没有用途而浪费。如何来充分利用计算机存储空间是软件工程中一个很重要的课题。
位段以位为单位定义结构体(或共用体)中成员所占存储空间的长度。
含有位段的结构体类型称为位段结构。
位段结构也是一种结构体类型,只不过其中含有以位为单位定义存储长度的整数
类型位段成员。采用位段结构既节省存储空间,又可方便操作。
位段结构中位段的定义格式为:
unsigned <成员名>:<二进制位数>
例如:
struct bytedata
{unsigned a:2; /*位段a,占 2 位*/
unsigned:6; /*无名位段,占 6 位,但不能访问*/
unsigned:0; /*无名位段,占 0 位,表下一位段从下一字边界开始*/
unsigned b:10; /*位段b,占 10 位*/
int i; /*成员i,从下一字边界开始*/
}data;
2.注意事项:
一般来讲,各个位段的长度没有限制,但是要注意位段的组织与存储方式。在使用位段的时候请注意如下问题:
1)位段成员必须为整型数据,包括有符号数和无符号数;位段的长度为大于等于零的整数常量。
2)位段长度为零的主要目的是使得下一成员从下一存储单元开始存放,本单元没有用完的单元空闲。
3)可以定义匿名字段,此位段仅仅用于占位,而不是使用。其主要的目的是为了满足将来系统升级或扩充的需要。例如
struct data
{
unsigned a:2
unsigned b:2
unsigned c:15
}
4)位段的长度不能够大于存储单元的长度,不能够定义位段数组。
5) 位段的引用,其实为位成员变量的引用,可以像使用整数变量一样使用,但是要注意存储空间的限制,即可存储数据的有效范围。
6)一个位段必须存储在同一存储单元(即字)之中,不能跨两个单元。如
果其单元空间不够,则剩余空间不用,从下一个单元起存放该位段。
7) 位段无地址,不能对位段进行取地址运算。
8) 位段可以以%d,%o,%x 格式输出。
9) 位段若出现在表达式中,将被系统自动转换成整数。
请参考以下网址:
http://its.nbtvu.net.cn/xhyu/cai_c/c_web/c/c8/c83.htm#c833
1、 位段成员只有三种类型:int ,unsigned int 和 signed int这三种(当然了,int 型位段是不是可以取负数不是我说了算的,因为这是和你的编译器来决定的。位段,位段,它是用来表示字段位长(bit)的,它只有整型值,不会有7.2这种 float 类型的,如果你说有,那你就等于承认了有 7.2个人这个概念,当然也没有 char 这个类型的);2、成员名后面的一个冒号和一个整数,这个整数指定该位段的位长(bit);3、许多编译器把位段成员的字长限制在一个 int 的长度范围之内;4、位段成员在内存的实现是从左到右还是从右到左是由编译器来决定的,但二者皆对。
3.例子:
先看一个例子: 我们需要用到五个变量。 假定, 其中三个用作标志, 称为 f1,
f2 和 f3。 第四个称为 type, 取值范围为 1 至 12。 最后一个变量称为 index, 值的范围为 0 至 500。
通常, 我们用下面的语句来说明这些变量:
char f1,f2,f3;
unsigned int type;
unsigned int index;
但是, 实际上标志 f1, f2, f3 分别只需要 1 位。变量 type 只需要 4 位, 而变量 index 只需要 9 位。 总共是 16 位 ---- 2 个字节。我们用两个字节就够了。
我们可这样来做:
struct packed_struct
{
unsigned int f1 :1;
unsigned int f2 :1;
unsigned int f3 :1;
unsigned int type :4;
unsigned int index :9;
};
该例中, 我们定义了一个结构 packed_struct。该结构定义了五个成员 。第一个成员叫做 f1, 是 unsigned int 类型的。紧跟在该成员名之后的 :1 规
定了它以 1 位存放。类似地, 标志 f2 和 f3 被定义为长度只有 1 位的。定义成员 type 占有 4 位。定义成员 index 占有 9 位。C 编译器自动地把上面的位段定义压缩在一起。位段的划分如图所示。packed_struct 总共使用了 16 位。这种方法的好处是, 定义成 packed_struct 类型的变量的位段, 可以如引用一般的结构成员一样方便地引用。同时, 使用了更少的内存单元数。
我们已经定义了一个称作为 packed_struct 的包含着位段的结构。现在, 我们
象下面那样定义一个称作为 packet_data 的变量: struct packed_struct
packed_data; 于是, 我们就可以用简单的语句, 把 packed_data 的 type 位段设置为 7: packed_data.type = 7; 类似地, 我们可以用下面的语句把这个位段的值设为 n: packed_data.type = n; 我们不必担心 n 的值太长, 以致不能放入 type 位段中, C 编译器会自动地仅取出 n 的低四位, 把它赋值给 packed_data.type。取出位段的值也自动地处理的, 因此语句 n = packed_data.type; 将从 packed_data 中取出 type 位段, 并把它的值赋给 n。
4.其它
在一般的表达式中可以使用位段, 此时, 位段自动地转换成整数。因此, 表达式 i = packed_data.index/5+1; 是完全有效的。
在包含位段的结构中, 也可以包括 "通常的" 数据类型。因此, 如果我们想定义
一个结构, 它包含一个 int, 一个 char, 和二个 1 位的标志, 那么, 下面的
定义是有效的:
struct table_entry
{
int count ;
char c;
unsigned int f1 :1;
unsigned int f2 :1;
};
当位段出现在结构定义中时, 它们就被压缩成字。如果某个位段无法放入一个字
中, 那么该字的剩余部分跳过不用, 该位段被放入下一个字中。使用位段时, 必
须注意下列事项:
1)在某些机器上, 位段总是作为 unsigned 处理, 而不管它们是否被说明成
unsigned 的。
2)大多数 C 编译器都不支持超过一个字长的位段。
3)位段不可标明维数; 即, 不能说明位段数组, 例如 flag:l[2]。
4)最后, 不可以取位段地址。原因是, 在这种情况不, 显然没有称作为 "位段指
针" 类型的变量。