当前位置:   article > 正文

【位段】位段和结构体的区别

【位段】位段和结构体的区别

文章目录

什么是位段 

位段的内存分配

规则

实例

结构体和位段成员共同出现


什么是位段 

      位段:C语言允许在一个 结构体 中以为单位来指定其成员所占 内存 长度。这是位段的定义,由于是自定义成员所占内存长度,所以采用位段结构有利于节省空间,方便操作。

        位段的声明和结构体较为类似,但是也有不同之处:

1、位段的成员只能是int、signed int、unsigned int、char类型的数据。(char也是整形家族的一员)

2、位段的每一个成员后面都要加上冒号和所占空间大小,格式为——“类型  变量名 : 数字;”,比如 int  a:5;    这就是位段里一个成员,其中5表示这个成员占5个比特位的空间。

3、结构体的对齐是为了高效率,与此同时就会浪费一些空间,而位段的设计是为了节省空间,所以在位段里面没有“对齐”这一说法。

         比如下方就是一个位段的例子,_a这个成员占了2个比特位,_b这个成员占了5个比特位,_c这个成员占了10个比特位,_d这个成员占了30个比特位:

  1. struct A
  2. {
  3. int _a : 2;//a成员占2个比特位
  4. int _b : 5;//b成员占5个比特位
  5. int _c : 10;
  6. int _d : 30;
  7. };

位段的内存分配

规则

        对于上方的例子,打印sizeof(struct A),得到的答案却是8(单位是字节),按照一般想法,struct A 这个位段的空间应该是2+5+10+30 =47 ,用6个字节的空间就能存放(1字节=8比特位),但是这里却用了8个字节,这是因为位段的内存分配也存在一些规律。

        1、位段开辟空间是一次开辟4个字节(成员为int 类型),或者一次开辟1个字节(成员为char型)。

        2、在不同环境下,对开辟空间的使用方式不确定,所以位段具有不可移植性。(比如在对于一个字节内部的8个比特位,存放数据时,是从低位到高位存放,还是从高位到低位存放。对于一个字节内部的比特位,存放的最后一个成员长度超过了空余的比特位空间,那么是全部用下一个字节的比特位存,还是将该字节存满,然后再把剩下的内容存在下一个字节的比特位。)

实例

        比如下方代码的位段(VS2019环境下):

  1. #include<stdio.h>
  2. struct B
  3. {
  4. char a:3;
  5. char b:4;
  6. char c:5;
  7. char d:4;
  8. };
  9. int main()
  10. {
  11. struct B wd = { 0 };
  12. wd.a = 10;
  13. wd.b = 12;
  14. wd.c = 3;
  15. wd.d = 4;
  16. return 0;
  17. }

        10的二进制表示是101012的二进制表示是11003的二进制表示是114的二进制表示是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字节大小,然后运行验证得知也是。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #define MAX_SIZE 2+3
  4. struct _Record_Struct
  5. {
  6. unsigned char Env_Alarm_ID : 4;
  7. unsigned char Para1 : 2;
  8. unsigned char state;
  9. unsigned char avail : 1;
  10. }*Env_Alarm_Record;
  11. int main()
  12. {
  13. printf("%d\n", sizeof(struct _Record_Struct));
  14. return 0;
  15. }

        本文的内容就到这里啦!!如果喜欢的话请一键三连哦!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/515895
推荐阅读
相关标签
  

闽ICP备14008679号