关闭

结构体拾遗补缺2:结构体的位域(位段)

398人阅读 评论(0) 收藏 举报
分类:

一、位域的定义

    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

位结构定义的一般形式为: 
struct  位结构名{ 
    数据类型 [变量名]: 整型常数;   //成员称为“位域”或者“位段”
    数据类型 [变量名]: 整型常数; 
} 位结构变量;

其中: 数据类型必须是整型(包括字符型)。 整型常数的范围是数据类型的长度, 如定义为short,则范围是1~16,也就是说,当定义一个short类型的成员位段时,它的整形常数取值范围必须在0-16之间,超出范围编译器将报语法错。具体范围如下:

类型 整形常数范围
char, unsigned char 1-8
short, unsigned short 1-16
int, unsigned 1-32
long, unsigned long 1-32

当然上面的范围值也可以是0,但是作用不同,后面会提到。


例如:

struct webpage{ 
    unsigned char incon: 8;      // incon占用低字节的0~7共8位
    unsigned char txcolor: 4;   // txcolor占用高字节的0~3位共4位
    unsigned char bgcolor: 3;  // bgcolor占用高字节的4~6位共3位
    unsigned char blink: 1;      // blink占用高字节的第7位
}ch;
printf("%d\n", sizeof(struct webpage));

输出结果:2。

 

2. 位域的对齐与计算

上面结构体大小为2,但是,为什么会是2呢?因为结构体必须要遵守对其原则(前面已经讲过),另外,位域也要遵守下面3个对齐原则

1). 若相邻位域变量的类型相同,且其位宽之和 不大于 变量类型宽度(在此严重强调,是类型位宽而不是成员变量sizeof,也不是类型的sizeof或者其他什么)大小,则:后面的变量将紧邻前一个变量存储,直到不能容纳为止;

    struct A

    {

        char a : 2;

        char b : 3;

        char c : 1;

    }

    ,该结构体占1个字节。
2). 如果相邻位域变量的类型相同,但其位宽之和 大于 变量类型宽度大小,则后面的成员将从新的存储单元开始,其偏移量为其类型大小的整数倍;

    struct B

    {

        char a : 3;

        char b : 4;

        char c : 2;

    }

    ,该结构体占2个字节。
3). 如果相邻的位域变量的类型不同,不同位域变量存放在不同的位域类型字节中(这一条其实会根据编译器的不同而采用不同的规则)。

例如:

    struct C
    {
        char a : 1;
        char b : 3;
        short c : 13;
        int d : 3;
    };

    ,该结构体占8个字节。

    总结,在组织位域各变量时,步骤如下:

    1)首先根据它们的变量类型(必须是整型char、short、int、long),遵循结构体的对齐原则,分配各类型的空间;

    2)然后,在每个类型内部,根据各变量的位长,遵循位域的对齐原则,进行分段。

 

    如果位域上的整形范围值是0,则下个位域从新的字节开始(即使是同类型的位域),如:

    struct bs
    {
        int a : 4;
        int : 0;      // 空域
        int b : 4;    // 从新字节开始存放
        int c : 4;
    } ;

    上面这个位域定义中,a占第一字节的4位,后4位填0表示不使用;b从新的字节(下一个int)开始,占用4位,c占用4位。上面位结构体占8个字节。

 

3. 位域的访问

    结构体的位域变量的访问与普通的结构体变量的访问相同。 例如: 访问下例位结构中的bgcolor成员可写成ch.bgcolor 进行访问: 
    struct A

    { 
        char a : 8;      
        char b : 4;   
        char c : 3;  
        char d : 1;      
    }m;

    访问结构体中的b,代码为:m.b;

    位域变量可以没有位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

    struct k
    {
        int a:1;
        int :2;    // 该2位不能使用
        int b:3;
        int c:2;
    };

    结构体的位域变量可以与其它普通的结构体变量一起使用,例如:
    struct A

    { 
        char name[8]; 
        int age; 
        char state : 1; 
        char pay : 1; 
    }workers;

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25023次
    • 积分:394
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:36篇
    • 译文:0篇
    • 评论:1条
    最新评论