【结构体位段问题】

85 阅读9分钟

7/100

发布文章

w2915w

加粗

斜体

标题

删除线

无序

有序

待办

引用

代码块

运行代码

图片

视频

表格

超链接

投票

导入

导出

保存

撤销

重做

模版

使用富文本编辑器

目录

发文助手

语法说明

<font color="red" size="3">每一位勇敢努力的少年,必将不负众望!</font>
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/75be1fd87fcb4196997fad7a1daa31fb~tplv-k3u1fbpfcp-zoom-1.image)



[什么是位段](#1)
	


 - [位段的详细解释](#11)


<h1 id ="1">


位段其实也是一种结构体的类型


1.位段的成员是 `int ,short int unsigned int , signed int , short , char` 类型


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


<h1 id = "11">


看一个例子:


```c
struct S
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};

int main()
{
	struct S s = { 0 };
	printf("%zd\n", sizeof(s));
	//%zd--打印无符号整型
}
```

那么来猜测一下打印出来的结果是多少呢?
或许你猜的是47,我们来看一下结果


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4b1fdb507674c6dae483797f0d0c7c6~tplv-k3u1fbpfcp-zoom-1.image)
打印出8的原因,在于下面:


其实 ,位段 -----位 ----二进制位
也就是说,冒号后面的数字,表示的是二进制数
我们先看整体,结构体中所有的成员都是int 类型,而int 类型是4字节,1字节是8个比特位,4字节就是32 比特位,


进入结构体内部,先创建了一个int类型的空间,



a占用2个比特位,b占用5个比特位,c占用10个比特位


abc在内存中的分布如下图:


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0df20e988b594eff98cf37e69ee95549~tplv-k3u1fbpfcp-zoom-1.image)


但此时这4字节中,剩下的比特位不够30个,存放不了b,所以还需再开辟一个int类型的空间,即4个字节,来存放d
(因为成员类型是int 类型,刚才一次性开辟了4个字节的空间)
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1cba95e4663545168cbda3992c83058f~tplv-k3u1fbpfcp-zoom-1.image)
在内存中从右向左存储


所以,总体成员内存布局如上图:
这里你可能会有个疑惑,为什么不是在c的后面开始占用空间?
因为第一次开辟了4个字节(一个int类型)的空间,存放了a,b,c后,发现剩下的空间不够存放d,所以另外再开辟4个字节的空间,从这新开辟的空间中存放d。所以灰色的区域就是浪费了。


还有一个问题,位段后面的数字能大于32 吗?
其实是不行的,一个int类型是4字节,32比特位,不能大于32,如果强行大于32呢?


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4d74a7d5d4b94b369d4ba29f1b6a6ea1~tplv-k3u1fbpfcp-zoom-1.image)


强行大于32就会报错。


**所以位段是用来节省空间的**


这里可能又有疑惑了,刚刚明明说浪费了灰色区域的空间,现在又说是节省空间,自相矛盾了。
	你可以想想,如果不使用位段,那么就会开辟4个int类型的空间,就会开辟16字节的空间,但是使用位段,只开辟了8字节的空间,你说是不是节省空间呢?


再来看一个例子:


```c
struct T
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;

};

int main()
{
	struct T t = { 0 };
	printf("%zd\n", sizeof(t));
	t.a = 10;
	t.b = 20;
	t.c = 3;
	t.d = 4;
	printf("%d %d %d %d", t.a, t.b, t.c, t.d);
}
```

请问输出的结果分别是什么呢?
第二个printf可能你脱口就说出,分别打印10 20 3 4 嘛
这么简单,而第一个printf ,有了第一个例子的参照,我们可以计算t的空间大小


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/33cc22614ec446aa9af243de5789c6c9~tplv-k3u1fbpfcp-zoom-1.image)
a和b在内存中的布局如图,由于c占5个比特位,剩余空间不足c使用,再开辟一个char 的空间


如下图:


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/36fbad1728fb44c296e8331872d5df9f~tplv-k3u1fbpfcp-zoom-1.image)
剩下的3个比特位又不足够d使用,d需要4个比特位,故再开辟一个char类型的空间



![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/24d83da4807d4c6b828919f33750853f~tplv-k3u1fbpfcp-zoom-1.image)
所以t的总大小是3个字节,第一个printf打印的是3,但是第二个printf真的是打印刚才说的
10 20 3 4 吗?
来看答案:
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/808e1153ca824f618f164826e86359e0~tplv-k3u1fbpfcp-zoom-1.image)
为什么会出现2 4 3 4 呢?好像毫不相干。


先听我解释:
t.a = 10,我们知道,a只需占用3个比特位, 而10 的二进制表示形式是 1010
占用3比特位,从右往左拿3 个,那就拿010,放入内存中。
如下图:
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a8adae2399614702a47cc70a231a4e0b~tplv-k3u1fbpfcp-zoom-1.image)
同理,t.b = 20, 20的二进制表示形式是  10100,从右往左,取4个,即0100,放入内存中,
t.c = 3 ,3的二进制表示形式是 011 ,从右往左,取5个,可是011不够五个呀,不够的那就补0就好了, 所以就取 00011 ,放入内存中,
t.d = 4 ,4 的二进制表示形式是  0100 ,放入内存中,所以,内存中的布局如图:


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f0e086b2da244038830cf8657d16cbb2~tplv-k3u1fbpfcp-zoom-1.image)



如何观察到这个现象呢? 内存中是以16进制展现出来的,我们就先分析一下
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63dc4e0ea4bf4f18ac31e93e6d698aa9~tplv-k3u1fbpfcp-zoom-1.image)


每4个二进制数就是一个16进制数,那么16进制数就是22 03 04 ,来验证结果:


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c8150cb512d74cf9888d0a3bc00a0c2e~tplv-k3u1fbpfcp-zoom-1.image)
完美符合预期:
打印出来是 2 4 3 4 的原因是:


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a4ad63d360b436bb0b63dcd088f698a~tplv-k3u1fbpfcp-zoom-1.image)


a,b,c,d的二进制序列化为十进制后就如上图,故打印的是2 4 3 4。


看到这里,你应该明白了位段是什么


不过,位段这个东西,是没有官方的标准规定的,在不同的平台,位段的使用也不同。


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f6a0859a22174eb18f2b8ffc57d7200e~tplv-k3u1fbpfcp-zoom-1.image)
**总结:跟结构相比,位段可以达到同样的效果,可以很好地节省空间,但是有跨平台问题的存在。**

每一位勇敢努力的少年,必将不负众望!
在这里插入图片描述

什么是位段

位段其实也是一种结构体的类型

1.位段的成员是 int ,short int unsigned int , signed int , short , char 类型

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

看一个例子:

struct S
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};

int main()
{
	struct S s = { 0 };
	printf("%zd\n", sizeof(s));
	//%zd--打印无符号整型
}

那么来猜测一下打印出来的结果是多少呢?
或许你猜的是47,我们来看一下结果

在这里插入图片描述
打印出8的原因,在于下面:

其实 ,位段 -----位 ----二进制位
也就是说,冒号后面的数字,表示的是二进制数
我们先看整体,结构体中所有的成员都是int 类型,而int 类型是4字节,1字节是8个比特位,4字节就是32 比特位,

进入结构体内部,先创建了一个int类型的空间,

a占用2个比特位,b占用5个比特位,c占用10个比特位

abc在内存中的分布如下图:

在这里插入图片描述

但此时这4字节中,剩下的比特位不够30个,存放不了b,所以还需再开辟一个int类型的空间,即4个字节,来存放d
(因为成员类型是int 类型,刚才一次性开辟了4个字节的空间)
在这里插入图片描述
在内存中从右向左存储

所以,总体成员内存布局如上图:
这里你可能会有个疑惑,为什么不是在c的后面开始占用空间?
因为第一次开辟了4个字节(一个int类型)的空间,存放了a,b,c后,发现剩下的空间不够存放d,所以另外再开辟4个字节的空间,从这新开辟的空间中存放d。所以灰色的区域就是浪费了。

还有一个问题,位段后面的数字能大于32 吗?
其实是不行的,一个int类型是4字节,32比特位,不能大于32,如果强行大于32呢?

在这里插入图片描述

强行大于32就会报错。

所以位段是用来节省空间的

这里可能又有疑惑了,刚刚明明说浪费了灰色区域的空间,现在又说是节省空间,自相矛盾了。
你可以想想,如果不使用位段,那么就会开辟4个int类型的空间,就会开辟16字节的空间,但是使用位段,只开辟了8字节的空间,你说是不是节省空间呢?

再来看一个例子:

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

};

int main()
{
	struct T t = { 0 };
	printf("%zd\n", sizeof(t));
	t.a = 10;
	t.b = 20;
	t.c = 3;
	t.d = 4;
	printf("%d %d %d %d", t.a, t.b, t.c, t.d);
}

请问输出的结果分别是什么呢?
第二个printf可能你脱口就说出,分别打印10 20 3 4 嘛
这么简单,而第一个printf ,有了第一个例子的参照,我们可以计算t的空间大小

在这里插入图片描述
a和b在内存中的布局如图,由于c占5个比特位,剩余空间不足c使用,再开辟一个char 的空间

如下图:

在这里插入图片描述
剩下的3个比特位又不足够d使用,d需要4个比特位,故再开辟一个char类型的空间

在这里插入图片描述
所以t的总大小是3个字节,第一个printf打印的是3,但是第二个printf真的是打印刚才说的
10 20 3 4 吗?
来看答案:
在这里插入图片描述
为什么会出现2 4 3 4 呢?好像毫不相干。

先听我解释:
t.a = 10,我们知道,a只需占用3个比特位, 而10 的二进制表示形式是 1010
占用3比特位,从右往左拿3 个,那就拿010,放入内存中。
如下图:
在这里插入图片描述
同理,t.b = 20, 20的二进制表示形式是 10100,从右往左,取4个,即0100,放入内存中,
t.c = 3 ,3的二进制表示形式是 011 ,从右往左,取5个,可是011不够五个呀,不够的那就补0就好了, 所以就取 00011 ,放入内存中,
t.d = 4 ,4 的二进制表示形式是 0100 ,放入内存中,所以,内存中的布局如图:

在这里插入图片描述

如何观察到这个现象呢? 内存中是以16进制展现出来的,我们就先分析一下
在这里插入图片描述

每4个二进制数就是一个16进制数,那么16进制数就是22 03 04 ,来验证结果:

在这里插入图片描述
完美符合预期:
打印出来是 2 4 3 4 的原因是:

在这里插入图片描述

a,b,c,d的二进制序列化为十进制后就如上图,故打印的是2 4 3 4。

看到这里,你应该明白了位段是什么

不过,位段这个东西,是没有官方的标准规定的,在不同的平台,位段的使用也不同。

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

语法说明

标题

文本样式

列表

图片

链接

目录

代码片

表格

注脚

注释

自定义列表

LaTeX 数学公式

插入甘特图

插入UML图

插入Mermaid流程图

插入Flowchart流程图

插入类图

快捷键

标题复制

# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题

Markdown 2992 字数 152 行数 当前行 1, 当前列 0

HTML 1731 字数 84 段落