【程序员面试宝典读书笔记】位域

时间:2022-11-14 15:04:35

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

一、位域定义与结构定义相仿,其形式为:

struct 位域结构名

{

     位域列表

};

其中位域列表的形式为: 类型说明符 位域名:位域长度

例如:

struct bs
{
   int a:8;
   int b:2;
   int c:6;
};

二、位域的几点说明:

1、一个位域必须存储在同一个存储单元中,不能跨两个单元。如果某存储单元空间中不能容纳下一个位域,则该空间不用,而从下一个存储单元起存放该位段。例如:

struct as
{
    unsigned a:4;
    unsigned b:29;//从下一单元开始存放
};

所以sizeof(as)=8;

struct bs
{
    unsigned a:4;
    unsigned b:27;
};

所以sizeof(bs)=4;

2、位域的长度不能大于数据类型本身的长度,比如int类型就能超过32位二进位,char类型就不能超过8位二进位。例如:

struct bs
{
    unsigned a:4;
    unsigned b:33;//出错
};

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

struct bs
{
    unsigned a:4;
    unsigned :3;//无名位域,不能使用
    unsigned b:5;
};

三、位域的对齐(摘自百度百科)

如果结构体中含有位域(bit-field),那么VC中准则是:

1、如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

2、如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

3、如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式:系统会先为结构体成员按照对齐方式分配空间和填塞(padding),然后对变量进行位域操作。

四、举例

#include <iostream>
using namespace std;

typedef struct A
{
        unsigned a:4;
        unsigned b:2;
        unsigned c:20; //当没有占满一个存储单元时,结构体的大小对齐为一个存储单元的大小
        unsigned d:7; //前面已经为26,故7+26>33已超过一个存储单元,所以7在一个新的存储单元存放
        unsigned e:28;//由于前面的7在一个新的存储单元的开头存放,且28+7>32, 故在另一个新的存储单元存放
        unsigned :3;//可以定义无名位段,此例中该无名位段占用3位的空间,该空间将不被使用       
};                  //由于前面的28在一个新的存储单元的开头存放,且28+3<32, 故不用在另一个新的存储单元存放
                     //所以最后求出的A的大小是4 + 4 + 4 =12
typedef struct B
{
        unsigned a:4;
        unsigned b:2;
        unsigned c:20;
        unsigned d:6;
        //unsigned i:1;当多出此行时,该结构体大小由4变为8,因为此行之前正好为32位
};

typedef struct C
{
        unsigned a:4;
        unsigned b:2;
        unsigned :0;    //定义长度为0的位段时不能指定名字,否则编译不过
        unsigned c:1;   //定义了0字段后,紧接着的下一个成员从下一个存储单元开始存放;
};                      //此例子中,c前面那个存储单元中的余下的26位中被0填充了
                       //所以最后求出的A的大小是4 + 4 = 8

int main()
{
        A a; B b;C c;
        cout<<"sizeof(a)="<<sizeof(A)<<endl;
        cout<<"sizeof(b)="<<sizeof(b)<<endl;
        cout<<"sizeof(c)="<<sizeof(c)<<endl;
        system("pause");
        return 0;
}

运行结果:

【程序员面试宝典读书笔记】位域

【程序员面试宝典读书笔记】位域