c语言编程,位域(bit field)的使用,方便位操作

c语言编程时,常用的最小单元是一个字节,而有时信息并不需要占用一个完整的字节,只需一个或几个 bit 即可。例如在存放一个开关量时,只有 0 和 1 两种状态, 用一个 bit 即可。位域就是为了方便解决这样的需求的,它方便我们进行 bit 级别的操作,也可以节约存储空间。

位域的定义方法

--

位域的定义和结构体的定义非常相似,形式如下

struct 位域结构名 
{ 
    位域列表 
    ...
}; 

例如,

struct BS
{
    char a:2;
    char b:6;
    char c:1,
         d:5,       // 注意,结尾是逗号
         :0;        // 该字节定义结束时,用分号
};

以上定义了两个字节的位域BS。第一个字节a占 2 个 bit,b占 6 个 bit。第二个字节c占 1 个 bit,d占 5 个 bit,该字节余下的 bit 用 0 填充。如果不想重复写变量的类型名,后面要用, 而不是 ;,每个字节的定义结束位置都以 ; 结尾。

位域的使用


这里以 c 语言实例来说明位域的使用和注意事项,demo 代码如下

// 文件名 t.c
#include <stdio.h>

typedef struct __BS
{
    char a:4;
    char :0;
    char b:4,
         c:4;
}BS;

typedef union un
{
    int i;
    BS  bs;
}UN;

int main()
{
    UN un = {0};

    BS* pBs = &(un.bs);
    pBs->a = 1;
    pBs->b = 2;
    pBs->c = 3;
    /* 以上 4 行与下面 3 行效果相同
    un.bs.a = 1;
    un.bs.b = 2;
    un.bs.c = 3;
    */
    printf("sizeof(BS): %ld\n", sizeof(BS));
    printf("un.bs.a: %d, x.b: %d, x.c: %d\n", un.bs.a, un.bs.b, un.bs.c);
    printf("un.i = %d\n", un.i);

    return 0;
}

编译,执行之,得到结果如下:

$ gcc -o t t.c 
$ ./t 
sizeof(BS): 2
un.bs.a: 1, x.b: 2, x.c: 3
un.i = 12801

通过代码,我们知道位域也是可以使用指针的。联合体中的 i 是 int 型的,打印出它的值,可以表示出位域中的值,例如上面打印出 12801,以 2 进制输出即为:

0011 0010 0000 0001

恰巧分别对应位域的 3 2 0 1。

输出顺序与运行机器是大端还是小端有关。

现在,我们队位域的定义做如下修改:

typedef struct __BS
{
    char a:4;
    char :0;
    char b:4,
         c:5;       // 修改为 5
}BS;

这样,第二个字节就存放不下 b 和 c 了。我们编译执行,看看会输出什么

$ vim t.c 
$ ./t 
sizeof(BS): 3
un.bs.a: 1, x.b: 2, x.c: 3
un.i = 197121

发现,位域变为 3 字节了,197121的二进制表示为

0011 0000 0010 0000 0001

很清楚了,当字节不足以容纳位域时,会自动从下一字节开始。

一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以通过无名域名使某位域从下一单元开始。
阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif