位段在使用中的注意点
-
位段的成员必须是int、unsigned int 、signed int、char、long(属于整型家族)
-
位段占的二进制位数不能超过该基本类型所能表示的最大位数
-
无名位段不能被访问,但是会占据空间
-
该结构占用的最少空间为其中最大类型所占的全部空间
-
不能对位段进行取地址操作
-
若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元(这里的位段存储单元经测试在VC环境下是4个字节,在linux下是1个字节)开始存放;
-
若位段出现在表达式中,则会自动进行整型升级,自动转换为int型或者unsigned int。
-
对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果
-
位段不能出现数组的形式
-
位段的空间上是按照4个字节(int)或者1个字节(char)的方式来开辟的
位段结构在内存中的存储方式
-
如果一个位段存储单元能够存储得下位段结构中的所有成员,那么位段结构中的所有成员只能放在一个位段存储单元中,不能放在两个位段存储单元中;如果一个位段存储单元不能容纳下位段结构中的所有成员,那么从剩余的位段从下一个位段存储单元开始存放。
-
如果一个位段结构中只有一个占有0位的无名位段,则只占1或0字节的空间(C语言中是占0字节,而C++中占1字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;
测试代码
/*测试位段 201110.12*/
#include<iostream>
using namespace std;
typedef struct node
{
unsigned int a:1; //存在一个非0位的位段,则至少占4Byte
}S;
typedef struct node1 //在C++中占1字节的空间 ,在C中占0字节
{
unsigned int :0;
}S1;
typedef struct node2
{
unsigned int a:1;
unsigned int :0; //下一个位段放在一个新的位段存储单元 ,所以占4+4=8Byte
unsigned c:32;
}S2;
typedef struct node3
{
unsigned int a:4;
unsigned int :0;
int :6; //这个位段放在一个新的位段存储单元
unsigned c:32; //由于6+32>32,所位段c也放在一个新的位段存储单元,所以占4+4+4=12Byte
}S3;
typedef struct node4
{
unsigned int a:1;
char b; //在一个位段存储单元中能够存下所有的成员,所以占4Byte
int c:1;
int d:2;
unsigned int e:2;
}S4;
int main(int argc, char *argv[])
{
S4 s4;
s4.a=1;
s4.c=1;
s4.d=2;
s4.e=3;
printf("%d %d %d %d\n",s4.a,s4.c,s4.d,s4.e);
printf("%d %d %d %d %d\n",sizeof(S),sizeof(S1),sizeof(S2),sizeof(S3),sizeof(S4));
return 0;
}
对于位段的不跨平台解释如下
- int位段被当成有符号或是无符号是不确定的(linux下是signed),对于取出的数据会进行符号扩展
typedef struct Data1
{
signed int a:5;
signed int b:2;
}data1;
int main(int argc, char ** argv)
{
data1 d;
d.a = 1;
d.b = 2;
printf("%d %d\n",d.a, d.b);
return 0;
}
结果为1, -2
-
位段中最大位的数目不能确定(16位机器最大16,32位机器最大32,如果数字写为27,在16位机器是不可以的);
-
位段中的成员在内存中是从左向右分配,还是从右向左分配尚未定义
总结
位段和结构相比,可以达到同样的效果,可以很好节省空间,但是存在不跨平台问题。