【C语言进阶】位段(结构体案例)

提示:小编建议读本篇博文之前先明白结构体大小的计算方法(结构体内存对齐)

 (下面的代码结果都是在VS2022环境测试结果

介绍:位段是以位为单位来定义结构体中成员变量所占的空间。采用位段结构既能够节省空间,又方便操作。

 位段与结构体的区别:

  1. 位段的成员只能是unsigned int、signed int、int、char类型的数据
  2. 位段的成员名后面必须有一个冒号和一个数字
  3. 位段是以位为单位,结构体是以字节为单位,位段相较于结构体更加节省了空间

 首先我们先简单看一下结构体与位段的区别图:

 

​
struct Stu
{
	int a : 4;//这里的4,代表4个比特位,而不是字节!
	int b : 5;//5个比特位
	int c : 9;//9个比特位
	int d : 28;//28个比特位
};

 上面代码中,其中里面的a为4个比特位,b为5个比特位,c为9个比特位,d为28个比特位,而不是字节!!!(其中一个字节等于8个比特位......

位段的介绍里面就说过,位段更加节省空间,那么按道理我们不妨大胆猜测一下!

上面的代码当中一共用了46个比特位,这样我们是不是可以认为需要一共需要6个字节就OK???

那我们看运行结果:

运行结果却可我们猜测的不同,其实位段的内存分配也是有规律的,接下来我们便可以研究一下位段的内存分配!!!


位段内存分配:

1.位段在空间上是按照4个字节(int)或者1个字节(char)来开辟空间的(32位系统)

2.位段是不跨平台的,注重可移植程序应该避免使用位段,因为它有许多不确定因素

解释第2条:

 

1.位段在不同的平台上储存方式是不确定的,比如上面代码,位段先一次性开辟了4个字节(因为里面是int类型,不是char类型),int a:4;int b:5; int c:9;  其中a、b、c一共占了18个比特位,剩余了14个比特位,而下面的int d:28; 中的是先使用这剩下14个比特位,再开辟4个字节来储存,还是直接开辟4个字节来储存,这是不确定的(不同的平台)。在储存数据方面,假如在一个字节(8个比特位)里面存放数据,是先从高位到低位存放数据,还是从低位到高位存放数据,这也是不确定的!

2.例如:C语言int类型在16位和32位单片机占的字节数是不同的,在32位系统当中为4个字节(小编用的就是32位系统),在16位系统当中是2个字节,所以上面图片当中的int d:28;中,d占了28个比特位(在32系统),如果把这个程序拿到16位系统中便会出错!因为int类型在16位系统当中一共才2个字节,也就是最大内存16个比特位,而这里有28个比特位,这是肯定会出错的!所以也凸显出一个关键,那就是赋予的内存大小不能超过规定大小!

3.int被当做无符号数还是有符号数在不同的平台是不确定的!

当我们熟悉上面的内容,我们就可以通过一些案例去计算我们(Vs2022环境下)的内存分配规律吧!

 案例:

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S ss = { 0 };
	ss.a = 16;
	ss.b = 12;
	ss.c = 3;
	ss.d = 8;
	return 0;
}

 大家都知道,在电脑当中数据是以二进制的形式储存的,在Vs环境下内存窗口是以16进制显示的,接下来我们就按照上面代码的过程一步一步的解析:

1.  ss.a=16      16的二进制为10000                         ss.b=12      12的二进制为1100                               ss.c=3          3的二进制为0011                            ss.d=8          8的二进制为1000

2.因为是char类型的数据,所以接下来系统首先会开辟一个字节!因为我们一开始初始化为0,所以描述为下图:

 

3.我们先假设二进制数据从低位往高位储存,第一个数据ss.a, 因为第一个数据限定了3个比特位,所以只能存放进去000,而且第一个字节存放完第一个数据后还剩下5个比特位,第二个数据是ss.b限定了4个比特位,第二个字节也可以存放下,所以存放进去1100,如图:

 4.当我们存放第三个数据的时候,发现第一个字节不够了,那我们先假设不用剩下的那个比特位,再开辟一个字节!当我们存放第三个数据ss.c,ss.c限定了5个比特位,存放进去数据为00011,存放第四个数据的时候,发现第二个字节在剩下3个比特位,那么按照上面的结果我们再开辟一个字节来存放第四个数据,第四个数据限定了四个比特位,存放进去1000,如图:

 

 所以我们假设一共用了3个字节!!!

 5.当我们假设这样的储存的时候,小编就用VS2022环境下测试结果:

 运行结果:

 发现我们的假设与测试结果完全相同!!!

那么我们就可以把这样的方法作为VS环境下位段储存方法。这样我们就明白了在Vs编译环境下的位段的计算方法了!

 

 拿出上面的代码,我们按照刚刚的方法分析会发现,一开始开辟4个字节(int 32位系统),整型a、b、c一共占了4个字节,而d自己占了4个字节!所以运行结果为8!!!


 结构体与位段联合的大小计算:

struct Stu
{
	char a : 4;
	char b : 3;
	int c;
	char d : 6 ;
};
int main()
{
	printf("%d\n", sizeof(struct Stu));
	return 0;
}

分析:上面前两个都是char类型位段成员,那么开辟一个字节(这时偏移量为0)存放第一个和第二个数据(位段不用考虑对齐),第三个数据为int类型的结构体成员,那么只能从偏移量为4的字节开始储存,第四个数据是位段成员,所以不用考虑字节对齐,所以自己存放在偏移量为8的空间,所以一共为9个字节,但里面有结构体成员,所以整体按照结构体的内存对齐来计算字节总大小,最大对齐数位4,而9不是4的倍数,所以一直增加为12!!!所以总占字节数位12.

 

运行结果: 


再强调一次!小编博客的计算过程全部为Vs编译环境!!!其他平台结果不一定准确.......

猜你喜欢

转载自blog.csdn.net/m0_73968621/article/details/129072576
今日推荐