🌟 前言
上一篇文章讲解了 结构体内存对齐,这篇文章讲讲结构体实现位段的能力
1. 什么是位段
位段的声明和结构是类似的,有两个不同:
1、位段的成员必须是 int
、unsigned int
或 signed int
。
2、位段的成员名后边有一个冒号和一个数字。
📝 位段示例
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
A 就是一个位段类型。
那位段 A 的大小是多少?
我们用 sizeof 看一下👇
为什么是 8 呢?
其实 位段 的 位 是指 二进制位;
int _a : 2
的意思是:_a
只占 2 个 bit 位;
int _b : 5
的意思是:_b
只占 5 个 bit 位;
int _c : 10
的意思是:_c
只占 10 个 bit 位;
int _d : 30
的意思是:_d
只占 30 个 bit 位;
那把所有的 bite 位加起来也就 47 个 bite 位,给 6(48 bit) 个字节完全够了呀!
为什么打印出来的是 8 个字节?也就是 64 个 bit 呢?
2. 位段的内存分配
1、 位段的成员可以是 int unsigned int
、signed 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
只需要 2 个 bit 呀,所以拿走 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;
};
首先,a
是 char 类型,不管三七二十一,先开辟 1 个字节也就是 8 bit 给它,但是 a
只需要 3 个 bit 呀,所以拿走 3 bit 以后,还剩 5 bit;
然后 b
需要 4 bit,所以从 5 bit 里面拿走 4 bit 以后,还剩下 1 bit;
其次 c
需要 5 bit,但是此时还剩下 1 bit 呀,完全不够,此时再单独开辟 1 个字节也就是 8 bit 给 c
用,所以拿走 5 bit 以后,还剩 3 bit;
最后 d
需要 4 bit,但是此时还剩下 3 bit 呀,完全不够,那么再单独开辟 1 个字节也就是 8 bit 给 d
用(上面剩下的 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,假设 a 在 8 bit 中,是从低位向高位使用的,也就是从右向左的方向,现在把 10 赋值给 a,10 的二进制是 1010,但是 a 的空间大小是 3 bit,所以只能存 3 bit,也就是存 010,最高位的 1 省去
b 里面要放 12,12 的二进制是 1100,但是 b 刚好有 4 bit,所以直接放进去,此时还剩下 1 bit,完全不够 c 使用了,那么再开辟 1 字节👇
c 占 5 bit,现在要把 3 放进去,3 的二进制是 011,但是 c 要占 5 bit 呀,所以前面添 0,也就是放 00011,此时还剩下 3 bit,完全不够 d 使用了,d 占 4 bit 那么再开辟 1 字节👇
d 占 4 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