C语言位域(位段)解析与实例分析.docx

上传人:王** 文档编号:1129893 上传时间:2024-04-02 格式:DOCX 页数:6 大小:28.83KB
下载 相关 举报
C语言位域(位段)解析与实例分析.docx_第1页
第1页 / 共6页
C语言位域(位段)解析与实例分析.docx_第2页
第2页 / 共6页
C语言位域(位段)解析与实例分析.docx_第3页
第3页 / 共6页
C语言位域(位段)解析与实例分析.docx_第4页
第4页 / 共6页
C语言位域(位段)解析与实例分析.docx_第5页
第5页 / 共6页
C语言位域(位段)解析与实例分析.docx_第6页
第6页 / 共6页
亲,该文档总共6页,全部预览完了,如果喜欢就下载吧!
资源描述

《C语言位域(位段)解析与实例分析.docx》由会员分享,可在线阅读,更多相关《C语言位域(位段)解析与实例分析.docx(6页珍藏版)》请在优知文库上搜索。

1、位域是什么?有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用O和1表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:1Structbs2unsignedm;3unsignedn:4;4unsignedcharch:6;5);后面的数字用来限定成员变量占用的位数。成员m没有限制,根据数据类型即可推算出它占用4个字节(Byte)的内存。成员n、Ch被:后面的数字限制,不能再根据数据类型计算长度,它们分别

2、占用4、6位(Bit)的内存。n、Ch的取值范围非常有限,数据稍微大些就会发生溢出,请看下面的例子:1include2intmain()3Structbs4unsignedm;5unsignedn:4;6unsignedcharch:6;7a=Oxad,OxE,*$,);8第一次输出9printf(%#x,%#x,%cna.m,a.n,a.ch);10更改值后再次输出1la.m=0xb8901c;12a.n=0x2d;13a.ch=,z;14printf(,%#x,%#x,%cnu,a.m,a.n,a.ch);15system(,pause);16return0;17)运行结果:Oxad,Ox

3、e,$0xb8901c,Oxd,:请按任意镇继续.对于n和ch,第一次输出的数据是完整的,第二次输出的数据是残缺的。第一次输出时,n、Ch的值分别是OxE、0x24($对应的ASCIl码为0x24),换算成二进制是1110、100100,都没有超出限定的位数,能够正常输出。第二次输出时,n、Ch的值变为0x2d、0x7aCZ对应的ASeIl码为0x7a),换算成二进制分别是IOIlO1、IlIlOl0,都超出了限定的位数。超出部分被直接截去,剩下IlOk111010,换算成十六进制为Oxd、0x3a(0x3a对应的字符是:)。C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲

4、,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。例如上面的bs,n的类型是UnSignedin3长度为4个字节,共计32位,那么n后面的数字就不能超过32;Ch的类型是UnSignedChar,长度为1个字节,共计8位,那么Ch后面的数字就不能超过8。我们可以这样认为,位域技术就是在成员变量所占用的内存中选出一部分位宽来存储数据。C语言标准还规定,只有有限的几种数据类型可以用于位域。在ANSlC中,这几种数据类型是intSignedint和Unsignedint(int默认就是Signedint);到了C99,_Bool也被支持了。但编译器在具体实现时都

5、进行了扩展,额外支持了char、SignedcharUnSignedChar以及enum类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。位域的存储C语言标准并没有规定位域的具体存储方式,不同的编译器有不同的实现,但它们都尽量压缩存储空间。位域的具体存储规则如下:当相邻成员的类型相同时,如果它们的位宽之和小于类型的SiZeof大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的SiZeOf大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。以下面的位域bs为例:1include2intmain()3Structbs4unsi

6、gnedm:6;5unsignednJ2;6unsignedp:4;7);8printf(%dn,sizeof(structbs);9retum0;10)运行结果:4信按任意键继续.m、np的类型都是unsignedint,sizeof的结果为4个字节(Byte),也即32个位(Bit)。m、n、P的位宽之和为6+12+4=22,小于32,所以它们会挨着存储,中间没有缝隙。SiZeOf(StrUCtbS)的大小之所以为4,而不是3,是因为要将内存对齐到4个字节,以便提高存取效率。如果将成员m的位宽改为22,那么输出结果将会是8,因为22+12=34,大于32,n会从新的位置开始存储,相对m的偏

7、移量是sizeof(unsignedint),也即4个字节。如果再将成员P的位宽也改为22,那么输出结果将会是12,三个成员都不会挨着存储。当相邻成员的类型不同时.,不同的编译器有不同的实现方案,GCC会压缩存储,而VC/VS不会。请看下面的位域bs:1#include2intmain()3Structbs4unsignedm:12;5unsignedcharch:4;6unsignedp:4;71;8printf(%dn,sizeof(structbs);9retum0;)在GeC下的运行结果为4,三个成员挨着存储;在VC/VS下的运行结果为12,三个成员按照各自的类型存储(与不指定位宽时的

8、存储方式相同)。m、ch、P的长度分别是4、1、4个字节,共计占用9个字节内存,为什么在VC/VS下的输出结果却是12呢?期待您的回复。如果成员之间穿插着非位域成员,那么不会进行压缩。例如对于下面的bs:1Structbs2unsignedm:12;3unsignedch;4unsignedp:4;5);在各个编译器下Sizeof的结果都是12。通过上面的分析,我们发现位域成员往往不占用完整的字节,有时候也不处于字节的开头位置,因此使用&获取位域成员的地址是没有意义的,C语言也禁止这样做。地址是字节(Byte)的编号,而不是位(Bit)的编号。无名位域位域成员可以没有名称,只给出数据类型和位宽

9、,如下所示:1Structbs2intm:12;3int:20;该位域成员不能使用4intn:4;5);无名位域一般用来作填充或者调整成员位置。因为没有名称,无名位域不能使用。上面的例子中,如果没有位宽为20的无名成员,m、n将会挨着存储,SiZeof(StnICtbS)的结果为4;有了这20位作为填充,m、n将分开存储,Sizeof(Structbs)的结果为8。在做嵌入式开发的时候,我们经常会遇到这样的代码:StructUnsignedintwidthValidated:1;UnsignedintheightValidated:1;status;这样定义结构体变量是什么意思呢?主要原因是:

10、有些信息在存储时,只需占几个或一个二进制位(bit),并不需要占用一个完整的字节。例如,在存放一个开关量时,只有O和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。位域:是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。位域定义与结构定义相仿,其形式为:StrUet位域结构名位域列表;其中位域列表的形式为:typemember_name:width;下面是有关位域中变量元素的描述:元素编述type只能为喊赘SI),

11、unsnd1nt(f5ffl3).*nednt侑仔号笈望)三蹴22.决定了如何解性位域的值.member-nate位SEK)名就Width位域中位的致.史度必须小于或等于擢定类型的位JSflL位域的使用和结构体成员的使用相同,其般形式为:位域变量名.位域名位域变量名-位域名位域最大的作用就是节省存储空间,在本质上就是一种结构类型,不过其成员是按二进位分配的。例如以下案例:#include#include/*定义简单的结构*structUnsignedintwidthValidated;UnsignedintheightValidated;Jstatusl;/*定义位域结构*structUnsi

12、gnedintwidthValidated:1;UnsignedintheightVaIidated:1;status2;intmain()printf(Memorysizeoccupiedbystatus1:%ldn,sizeof(status1);printf(,Memorysizeoccupiedbystatus2%ldn,sizeof(status2);retum;)代码被编译和执行时,它会产生下列结果:devDESKT0P-GD47KAl:-/gcc,Mgcctest.cdevgDESKT0P-GD47KAl:/gcc/MfMYWr*/c1toCLLiICl4hi/r+d:/2eaQ

13、$./a.out结构体Statusl是由正常的两个Unsignedint类型变量组成,占用内存是8字节,结构体StatUS2也是UnSignedint类型变量,但是它仅使用了一个UnSignedint类型内存的前2bit,实际上还有30bit没使用,所以占用内存是4字节。对于位域的定义有以下几点说明:1 .一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:Structbsunsigneda:4;UnSigned:4;/*空域*/unsignedb:4;/*从下一单元开始存放*unsignedc4)在这个位域定义

14、中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。2 .位域的宽度不能超过它所依附的数据类型的长度,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。3 .位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:Structkinta:1;int:2;/*2位不能使用*/intb:3;intc:2;4 .当相邻成员的类型相同时,如果它们的位宽之和小于类型的SiZeOf大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的SiZeOf大小,那么后面的成员将从新的存储单元

15、开始,其偏移量为类型大小的整数倍。例如:includeintmain()Structbsunsignedm:6;unsignedn:12;unsignedp:4;printf(%ldnn,sizeof(structbs);returnO;运行结果:devfDESKT0P-GD47KAl:/gcc/f$gcctest.Cm、n、p的类型都是Unsignedintsizeof的结果为4个字节(Byte),也即32个位(Bit)om、n、P的位宽之和为6+12+4=2的小于32,所以它们会挨着存储,中间没有缝隙。5 .当相邻成员的类型不同时,不同的编译器有不同的实现方案,GCC会压缩存储,而VC/VS不会。例如:includeintmain()Structbsunsi

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 数据结构与算法

copyright@ 2008-2023 yzwku网站版权所有

经营许可证编号:宁ICP备2022001189号-2

本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!