/**
* cppTest-4.1:位域
*
*参考了百度百科的资料后,终于搞清楚了位域的问题!!!
*这个例子涉及到了位域的基本特性、符号特性、对齐规则、大小计算、空域、无名位域等问题。
*
*所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。
* 每个域有一个域名,允许在程序中按域名进行操作。
* 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
* author 炜sama
*/
#include<stdio.h>
#include<iostream.h>
int main(){
cout<<"位域的一般情况"<<endl;
struct bf0{
unsigned a:1;
unsigned b:3;
unsigned c:4;
//double d:1;//错误!位域只能是有序数据类型!(char,short,int,long)
//unsigned e:33;//错误!定义时委员宽度不能超过unsigned的类型长度!
}bit,*pbit;
bit.a=1;
bit.b=7;
bit.b=18;//赋值时超过位域长度的部分自动截掉
bit.c=15;
//位域里的数据可以按任意类型输出
printf("%d,%d,%d\n",bit.a,bit.b,bit.c);
pbit=&bit;
pbit-> a=0;
pbit-> b&=3;
pbit-> c|=1;
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);
cout<<"位域符号问题"<<endl;
struct bf02{
int a:1;
int b:2;
int c:13;
};
bf02 b02;
b02.a=(int)1;
b02.b=(int)2;
b02.c=(int)3;
cout<<b02.a<<","<<b02.b<<","<<b02.c<<endl;//结果是-1,-2,3 !!!而不是1,2,3!!!
//原因:有符号数在机器中是以补码的形式存在的,其正负的判断有其规则。
//位域是以原码的形式来进行操作的,这中间有差异,造成了上面的结果。
//而关于位域的正负数判断,也不是简单的首bit的0或1来决定,否则上面的结果就应该是-1 -2 -3或者1 2 3了。
//位域的实现,是编译器相关的。建议是,使用位域不要使用正负这样的特性,即最好是使用如下的unsigned:
struct bf03{
unsigned a:1;
unsigned b:2;
unsigned c:13;
};
bf03 b03;
b03.a=(unsigned)1;
b03.b=(unsigned)2;
b03.c=(unsigned)3;
cout<<b03.a<<","<<b03.b<<","<<b03.c<<endl;//1,2,3
cout<<"如果相邻位域字段的类型相同,且其位宽之和<=类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止"<<endl;
struct bf1{
//char类型大小为8位
char a:1;
char b:2;
char c:5;
};
cout<<sizeof(bf1)<<endl;//1
struct bf12{
//int类型大小为32位
int a:8;
int b:8;
int c:8;
int d:1;
};
cout<<sizeof(bf12)<<endl;//4
cout<<"如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍"<<endl;
struct bf2{
//char类型大小为8位
char a:1;
char b:2;
char c:5;
char d:1;
};
cout<<sizeof(bf2)<<endl;//2
struct bf22{
//int类型大小为32位
int a:8;
int b:8;
int c:8;
int d:9;
};
cout<<sizeof(bf22)<<endl;//8
cout<<"如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式"<<endl;
struct bf3{
char a:1;
char b:2;
char c:5;
int d:1;
};
cout<<sizeof(bf3)<<endl;//8
struct bf32{
char a:1;
int d:1;
};
cout<<sizeof(bf32)<<endl;//8
struct bf33{
int d:1;
char a:1;
};
cout<<sizeof(bf33)<<endl;//8
struct bf34{
int d:1;
//char a:1;
short s:1;//short的长度为2字节!
long l:1;//在这里long型为4字节长度!!!
};
cout<<sizeof(bf34)<<endl;//12
struct bf342{
int i:1;
long l:1;//在这里long型为4字节长度!!!
int i2:1;
};
cout<<sizeof(bf342)<<endl;//4!long的长度与int的一样,所以结果是4而不是12!看来是根据数据类型长度来对齐的而不是数据类型类别!
struct bf35{
char c0:8;
int i:32;
char c1:8;
char c2:8;
//double d:1;//错误!位域只能是有序数据类型!!!
};
cout<<sizeof(bf35)<<endl;//12。注意与bf3的区别!
struct bf36{
char c0:8;
int i:32;
char c1:8;
char c2:8;
char c3:7;
char c4:2;
char c5:8;
int i2:1;
int i3:1;
};
cout<<sizeof(bf36)<<endl;//20。注意与bf35、bf3的区别!
//到这里已经可以推断出位域在vc6里的排放规则了!:
//1、以长度最长的数据类型的大小为对齐大小l(形象地把它想象成一行数组);
//2、相同类型的位域才能排在同一行,如果l不够放,那剩下的另起一行排放;
//3、如果有另外不同类型的位域插入,那这个不同的位域要另起一行排放,而不是接着排在之前的l里;
//4、最后算出来的sizeof一定是l的倍数!
cout<<"空域问题"<<endl;
struct bfk1{
char a:1;
char :0;//空域的定义格式
};
cout<<sizeof(bfk1)<<endl;//结果是1!!!
struct bfk13{
char c:1;
char :0;//空域的定义格式
char c1:1;
};
cout<<sizeof(bfk13)<<endl;//结果是2!!!
struct bfk14{
char c:8;
char :0;//空域的定义格式
};
cout<<sizeof(bfk14)<<endl;//结果是1!!!
struct bfk15{
char c:8;
char :0;//空域的定义格式
char :0;//空域的定义格式
char :0;//空域的定义格式
int i:1;
};
cout<<sizeof(bfk15)<<endl;//结果是8!!!
struct bfk16{
char :0;//空域的定义格式
int i:31;
int i2:1;
char c:8;
};
cout<<sizeof(bfk16)<<endl;//结果是8!!!
struct bfk17{
char c:8;
int :0;//空域的定义格式
};
cout<<sizeof(bfk17)<<endl;//结果是4!!!
//到这里这里可以总结出vc6里空域的占位规则了:
//对齐规则与一般情况下一样,不同的是——
//1、空域放在最前和最后时,不占位;
//2、空域放在中间时,如果有连续n个空域,那会合并为一个空域;
//3、空域会补齐当前“行”的空位;
//4、空域的类型无关紧要,唯一的作用是是否可以决定最长“行长度”l。例如bfk17的情况。
cout<<"无名位域问题"<<endl;
struct bfw1{
char a:1;
char :8;//无名位域的定义格式
};
cout<<sizeof(bfw1)<<endl;//结果是2!!!
struct bfw2{
char a:1;
int :8;//无名位域的定义格式
int :32;//无名位域的定义格式
};
cout<<sizeof(bfw2)<<endl;//结果是12!!!
struct bfw3{
int :8;//无名位域的定义格式
char a:1;
int :32;//无名位域的定义格式
};
cout<<sizeof(bfw3)<<endl;//结果是12!!!
//无名域的占位情况与空域很相似
return 0;
}
cppTest-4.1:位域
最新推荐文章于 2022-11-13 23:00:49 发布