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

文章目录

什么是位段 

位段的内存分配

规则

实例

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


什么是位段 

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

#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;
}

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力努力再努力.xx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值