位段是通过结构体实现的,可以在一定程度上减小空间浪费,位段的声明和结构体类似,有以下几个不同:
①位段的成员必须是整形(int,char,short等)。
②成员后边有冒号和数字,表示该成员占几个bit位。
位段的内存分配
我们知道结构体存在内存对齐的说法,会浪费一定的空间,那么位段的内存是怎么分配和使用的呢,位段的空间是按照需要以四个字节(int)或一个字节(char)的方式开辟的,下面来举例说明一下:
struct A
{
//这里由于成员类型是int,所以一次要开辟四个字节,也就是32bit
int a:2;
int b:5;
//a和b占用7个bit,剩下25个bit不够c的,需要再开辟四个字节,所以总大小是8个字节
int c:30;
}
struct S
{
//这里由于成员是char类型,先开辟一个字节,也就是8bit
char a:3;
char b:4;
//a和b用掉7bit,到c的时候还剩1bit,不够,需要再开辟一个字节,在vs编译器下,这里剩下的一个bit会浪费掉,c从新开辟的8bit中使用5bit
char c:5;
//c用完后还剩3bit,不够d用,还需要再开辟一个字节,所以一共需要三个字节
char d:4;
}
//如果c用掉第一个字节的最后一个bit,开辟新字节c只需要四个bit,剩下四个bit给d刚好,
//就可以少开辟一个字节,但是vs编译器就是会浪费掉用不完的字节,如果剩余字节不够,就从新开辟的字节开始使用
了解了需要开辟多少空间,那么这些空间是怎么使用的呢:
上图中开辟了三个字节的空间,可以看出每个字节都是从右往左开始使用,a占用了第一个字节的右边三位,b占用了第一个字节的中间四位,第一个字节的最左边一位浪费了,c占用了第二个字节的右边五位,第二个字节左边三位浪费,d占用了第三个字节的右边四位,第三个字节的左边四位浪费,a只有三位,无法存储1010,所以产生了截断,只存储了010。
位段使用中的问题
位段在使用中是存在一些隐患的:
①int位段被当成有符号数还是无符号数是不确定的,最好加上signed或unsigned。
②位段中最大位的数目不能确定(16位机器最大位数为16,32位机器最大位数为32),如果在16位机器中位的数目写的大于16会出问题。
③位段中的成员从左向右使用内存还是从右向左是不确定的(上面可以看出vs编译器是从右向左使用每个字节)。
④当前一个位段剩余位无法容纳下一个位段,开辟新空间后,后面的位段是舍弃剩余位还是使用剩余位,这一点也是不确定的(vs编译器是舍弃)。
位段可以在满足结构体需求的前提下减小空间消耗,但是跨平台使用存在一些风险。