文章目录
- 前言
- [1. 位段的含义](#1. 位段的含义)
- [2. 位段的声明](#2. 位段的声明)
- [3. 位段的内存分配(重点)](#3. 位段的内存分配(重点))
-
- [3.1 存储方向的问题](#3.1 存储方向的问题)
- [3.2 剩余空间利用的问题](#3.2 剩余空间利用的问题)
- [4. 位段的跨平台问题](#4. 位段的跨平台问题)
- [5. 位段的应用](#5. 位段的应用)
- [6. 总结](#6. 总结)
前言
相信大部分的读者在学校或者在自学时结构体的知识时,可能很少会听到甚至就根本没有听过一个知识点,那就是位段。
本文就给大家揭开位段的神秘面纱。🎶💖💖
1. 位段的含义
位段中的"位",指的是比特位(bit)。也就是说,我们可以通过位段指定变量所占内存空间的大小,而这个单位就是bit。
可能上面这么讲,你还是很疑惑。那我就举个例子:
假如我现在有个整型变量i,我知道它未来的赋值情况只可能是0,1,2,3这四个整数。那如果我们直接用4个字节去存储,未免有点浪费了。仔细再想一下,0,1,2,3,这四个数字,我有两个比特位就可以完整的表示出来了,没有必要用32个比特位。
那看到这里,有的读者读者就会说,位段这么好,那我是不是可以随意使用。答案我们在后面揭晓!
2. 位段的声明
位段的声明与结构体相类似。不过需要注意以下几点:
1.位段的成员必须得是int、unsigned int、signed int、char数据类型,在C99的标准中了可以是其他的数据类型。
- 位段成员名后必须得有冒号和一个数字。
比如:
c
struct S
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
这个变量名有个下划线,不是硬性规定,大家可以按照自己的习惯来编写。
那么此时,S就是一个位段类型。
那在这里我们就得思考一个问题了,位段S所占内存空间的大小是多少?
这里我先给出结果,大家可以慢慢思考。
3. 位段的内存分配(重点)
根据上面给出的结果,相信不少读者就会产生疑惑了。那接下来,我们就来聊一聊为什么会是这样的。
其实有个我上面讲过的知识点,可以作为我们寻求问题答案的突破口:
- 位段成员必须得是int、signed int、unsigned int 、char的数据类型。
- 位段的空间上是按照以4个字节(int)或者是1个字节(char)的方式来开辟的。
- 位段涉及到很多不确定的因素,位段是支持跨平台使用的,注重可以移植性的程序应该避免使用位段。
那接下我有一段代码,给大家讲一讲位段在内存中是如何开辟空间的。
c
#include<stdio.h>
struct S
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
int main()
{
//一个例子
struct S s = { 0 };
s._a = 10;
s._b = 12;
s._c = 3;
s._d = 4;
//空间是如何开辟的
return 0;
}
3.1 存储方向的问题
位段在存储数据时,是先申请1个字节或4个字节的空间,等到这些字节空间放满时才会申请下一个字节(一样的大小)的空间。
提醒:本文以4个字节的大小来开辟内存。
这样就不得不思考一个问题,我们申请到的内存空间是从左边开始存放比特位呢 ?还是从右边开始呢 ?答案是:不确定。
那既然是不确定我们就假设从右边 开始吧,请看图解
3.2 剩余空间利用的问题
当我们向内存存放到第四个变量_d时,发现剩下的空间不够存放_d了,此时编译器会再开辟一块4个字节大小的空间,用来继续存放剩余的成员。
可此时我们又得思考一个问题了,那就是之前还剩下一部分内存空间没有使用,是接着使用呢 ?还是直接在新开辟的内存区域中使用呢 ?答案是:不确定
那我们就假设从直接在新开辟的内存区域中存放数据。
根据编译器(以VS为例)读取数据的方式(每4个bit算作一个16进制数),我们可以猜到它在内存中存储的样子:
那此时应该是:00 00 01 B2 00 00 00 04 (VS的采用的时小端存储模式)
可以看到,我们的假设是成立的。在VS的环境下,确实是从申请空间的右边开始存放,并且当还有剩余的内存空间时,不会再继续使用,而是在新开辟的空间上使用。
讲到这里,相信你已经对位段的内存空间分配已经有了个清楚的认识。
4. 位段的跨平台问题
在上面我们讲了位段的不确定性,正是这些不确定性造成了位段的跨平台问题。
- int 位段被当成有符号数还是⽆符号数是不确定的。
- 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
- 位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。
- 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是弃
剩余的位还是利⽤,这是不确定的。
5. 位段的应用
我们学会了位段该如何使用,那我们不妨在了解一下,位段在我们实际生产生活中时如何使用的。
一个最典型的例子,网络各种协议的封装:
后面的那些数字,就是使用位段才能产生效果。那至于为什么会是这样子的,这里就请各位读者下来自己去了解了。
6. 总结
我们在之前讲过了结构体的内存对齐,这是一种用空间换取时间的一种做法。而在本文的位段,则是用时间来换取了空间。二种不同的策略,希望读者们能够自己慢慢领会。
最后,如果觉得本文写的还不错的话,请不要吝啬你们手中的赞哦!!!💖💖💖
学习很难,但坚持一定很酷。😊