6

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

 3 years ago
source link: https://blog.popkx.com/c-programming-use-of-bit-field/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

发表于 2018-07-24 20:07:50   |   已被 访问: 786 次   |   分类于:   C语言   |   暂无评论

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语言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK