【结构体内功修炼】结构体实现位段(二)

导读:本篇文章讲解 【结构体内功修炼】结构体实现位段(二),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

在这里插入图片描述

在这里插入图片描述

🌟 前言

上一篇文章讲解了 结构体内存对齐,这篇文章讲讲结构体实现位段的能力

1. 什么是位段

位段的声明和结构是类似的,有两个不同:

1、位段的成员必须是 intunsigned intsigned int

2、位段的成员名后边有一个冒号和一个数字。

📝 位段示例

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

A 就是一个位段类型。

那位段 A 的大小是多少?

我们用 sizeof 看一下👇
在这里插入图片描述
为什么是 8 呢?

其实 位段 是指 二进制位

int _a : 2 的意思是:_a 只占 2bit 位;

int _b : 5 的意思是:_b 只占 5bit 位;

int _c : 10 的意思是:_c 只占 10bit 位;

int _d : 30 的意思是:_d 只占 30bit 位;

那把所有的 bite 位加起来也就 47bite 位,给 6(48 bit) 个字节完全够了呀!

为什么打印出来的是 8 个字节?也就是 64bit 呢?

2. 位段的内存分配

1、 位段的成员可以是 int unsigned intsigned int 或者是 char (属于整形家族)类型

2、位段的空间上是按照需要以 4 个字节( int )或者 1 个字节( char )的方式来开辟的。

3、位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

还是看刚刚这段代码

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

首先,_a 是整型,不管三七二十一,先开辟 4 个字节也就是 32 bit 给它,但是 _a 只需要 2bit 呀,所以拿走 2 bit 以后,还剩 30 bit

然后 _b 需要 5 bit,所以拿走 5 bit 以后,还剩下 25 bit

其次 _c 需要 10 bit,所以拿走 10 bit 以后,还剩下 15 bit

最后 _d 需要 30 bit,但是此时还剩下 15 bit 呀,完全不够,那怎么办呢?此时再单独开辟 4 个字节也就是 32 bit_d 用(上面剩下的 15 bit 就不会再使用了);

所以 sizeof 求大小的时候,也就是 8 字节。

上面解释了 整型 的位段开辟,那如果当结构体的成员是 char 类型呢?

📝 代码示例

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};

首先,achar 类型,不管三七二十一,先开辟 1 个字节也就是 8 bit 给它,但是 a 只需要 3bit 呀,所以拿走 3 bit 以后,还剩 5 bit

然后 b 需要 4 bit,所以从 5 bit 里面拿走 4 bit 以后,还剩下 1 bit

其次 c 需要 5 bit,但是此时还剩下 1 bit 呀,完全不够,此时再单独开辟 1 个字节也就是 8 bitc 用,所以拿走 5 bit 以后,还剩 3 bit

最后 d 需要 4 bit,但是此时还剩下 3 bit 呀,完全不够,那么再单独开辟 1 个字节也就是 8 bitd 用(上面剩下的 3 bit 就不会再使用了);

所以 sizeof 求大小的时候,也就是 3 字节。

我们用 sizeof 看一下👇
在这里插入图片描述

既然学会了位段,那我们再来分析一下下面这段代码👇

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};

int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

	return 0;
}

上面我们已经计算过了,这个结构体开辟了 3 个字节,然后在主函数里面把这个 s 初始化为 0,这样就意味着,这 3 个字节里面,每一个 bit 位都为 0
在这里插入图片描述
首要为 a 开辟 1 个字节,a 只占其中的 3 bit,假设 a8 bit 中,是从低位向高位使用的,也就是从右向左的方向,现在把 10 赋值给 a10 的二进制是 1010,但是 a 的空间大小是 3 bit,所以只能存 3 bit,也就是存 010,最高位的 1 省去
在这里插入图片描述
b 里面要放 1212 的二进制是 1100,但是 b 刚好有 4 bit,所以直接放进去,此时还剩下 1 bit,完全不够 c 使用了,那么再开辟 1 字节👇
在这里插入图片描述
c5 bit,现在要把 3 放进去,3 的二进制是 011,但是 c 要占 5 bit 呀,所以前面添 0,也就是放 00011,此时还剩下 3 bit,完全不够 d 使用了,d4 bit 那么再开辟 1 字节👇
在这里插入图片描述
d4 bit,现在要把 4 放进去,4 的二进制是 100,但是 c 要占 4 bit 呀,所以前面添 0,也就是放 0100👇
在这里插入图片描述
此时主函数里面的代码已经走完了,那么内存里面到底存放的是什么呢?

由于二进制不好观看,我们换算成十六进制👇
在这里插入图片描述
那么内存里面到底存的是不是这个呢?我们可以调试看一看
在这里插入图片描述

3. 位段的跨平台问题

1、 int 位段被当成有符号数还是无符号数是不确定的。

2、位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。)

3、位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4、当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的。

总结:跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

4. 位段的应用

那么位段应用在那些地方呢?比如下面这张网络中经典的 IP 数据报👇
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80865.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!