赞
踩
文章目录
位段:C语言允许在一个 结构体 中以位为单位来指定其成员所占 内存 长度。这是位段的定义,由于是自定义成员所占内存长度,所以采用位段结构有利于节省空间,方便操作。
位段的声明和结构体较为类似,但是也有不同之处:
1、位段的成员只能是int、signed int、unsigned int、char类型的数据。(char也是整形家族的一员)
2、位段的每一个成员后面都要加上冒号和所占空间大小,格式为——“类型 变量名 : 数字;”,比如 int a:5; 这就是位段里一个成员,其中5表示这个成员占5个比特位的空间。
3、结构体的对齐是为了高效率,与此同时就会浪费一些空间,而位段的设计是为了节省空间,所以在位段里面没有“对齐”这一说法。
比如下方就是一个位段的例子,_a这个成员占了2个比特位,_b这个成员占了5个比特位,_c这个成员占了10个比特位,_d这个成员占了30个比特位:
- struct A
- {
- int _a : 2;//a成员占2个比特位
- int _b : 5;//b成员占5个比特位
- int _c : 10;
- int _d : 30;
- };
对于上方的例子,打印sizeof(struct A),得到的答案却是8(单位是字节),按照一般想法,struct A 这个位段的空间应该是2+5+10+30 =47 ,用6个字节的空间就能存放(1字节=8比特位),但是这里却用了8个字节,这是因为位段的内存分配也存在一些规律。
1、位段开辟空间是一次开辟4个字节(成员为int 类型),或者一次开辟1个字节(成员为char型)。
2、在不同环境下,对开辟空间的使用方式不确定,所以位段具有不可移植性。(比如在对于一个字节内部的8个比特位,存放数据时,是从低位到高位存放,还是从高位到低位存放。对于一个字节内部的比特位,存放的最后一个成员长度超过了空余的比特位空间,那么是全部用下一个字节的比特位存,还是将该字节存满,然后再把剩下的内容存在下一个字节的比特位。)
比如下方代码的位段(VS2019环境下):
- #include<stdio.h>
- struct B
- {
- char a:3;
- char b:4;
- char c:5;
- char d:4;
- };
-
- int main()
- {
- struct B wd = { 0 };
- wd.a = 10;
- wd.b = 12;
- wd.c = 3;
- wd.d = 4;
- return 0;
- }
10的二进制表示是1010,12的二进制表示是1100,3的二进制表示是11,4的二进制表示是100 。下面又流程图,配合文字理解。
第一步:位段里的成员是char类型的,所以先开辟1个字节的空间,拿出三个比特位放a,然后涉及到了上方规律的第二条,我们假设VS2019环境下是从低位开始存储。然后拿4个比特位放b。此时第一次开辟的空间只剩下1个比特位,但是需要5个比特位放c,这时候又涉及到上方规律第二条(是把剩下一个比特位存满,还是新开辟内存再存),我们假设是新开辟空间然后存放c,那么又一次新开辟1个字节的空间,从低位开始,拿出5个比特位存放c。然后到d,同c,新开辟空间存放。如下方第一张图。(三个字节的空间实际是连在一起的,这样画是易于理解。)
第二步:空间开辟了,然后存放数据,a的值二进制表示是1010,但是只有3个空间来存放,所以实际上存的是010,b的值存的是1100,c的值存的是00011,d的值存的是0100。然后其他地方没有内容,故为0。如下方第二张图。
第三步:验证。如果这样的假设是正确的,根据数据的存储方法,三个字节的内容分别是01100010 、00000011、00000100,(如下第二张图里面的),那么按照其在内存中的存储,是十六进制,四个比特位一起,故是0110、0010、0000、0011、0000、0100,翻译成十六进制就是6、2、0、3、0、4,所以存储起来就是 62 03 04 ,那么我们VS2019下调试,监视地址如下面第三张图、验证成功,说明VS2019环境下确实是这么存储的。
到这里我不禁有疑惑,如果一个结构体里面出现位段成员,那么这样子的声明是合法的吗,于是尝试了一下,发现可以,如下一段代码和运行结果,结构体成员和位段成员共同出现,求该结构体大小,那么根据常规思路来看:
1、一开始是char类型的位段成员,那么分配一个字节空间(偏移量为0),然后前两个位段成员都可以放在这一个字节的空间里面。
2、第三个成员是结构体成员,char类型,对齐数是1(不明白什么是对齐数的话,可以看前面关于结构体的博客,结构体的对齐内容),所以对齐到1的倍数,由于偏移量为0的字节已经存放内容,所以该成员放在偏移量为1的空间里面。
3、第四个成员是位段成员,这时候不需要考虑对齐,所以直接在后面开辟一个空间(该空间偏移量为2),成员类型是char,所以分配1个字节的空间,足够存第四个成员。
4、由上三步得知,这个类型开辟的空间是3字节大小,然后运行验证得知也是。
- #include<stdio.h>
- #include<stdlib.h>
- #define MAX_SIZE 2+3
- struct _Record_Struct
- {
- unsigned char Env_Alarm_ID : 4;
- unsigned char Para1 : 2;
- unsigned char state;
- unsigned char avail : 1;
- }*Env_Alarm_Record;
-
-
- int main()
- {
- printf("%d\n", sizeof(struct _Record_Struct));
- return 0;
- }
本文的内容就到这里啦!!如果喜欢的话请一键三连哦!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。