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


    在这里插入图片描述

    在这里插入图片描述

    🌟 前言

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

    1. 什么是位段

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

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

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

    📝 位段示例

    struct A
    {
    	int _a : 2;
    	int _b : 5;
    	int _c : 10;
    	int _d : 30;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    首先,_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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    首先,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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面我们已经计算过了,这个结构体开辟了 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 数据报👇
    在这里插入图片描述

  • 相关阅读:
    CentOS 同时安装多个版本的Python3
    20220802NOI模拟赛--考后总结
    当我看源码的时候,我在想什么?
    C++入门教程(一、初步了解)
    网关、网桥、路由器和交换机之【李逵与李鬼】
    第十八章《JDBC》第4节:数据库连接池
    003 PythonTCP网络通信
    ContentType:application/x-www-form-urlencoded请求方法遇到的坑【PHP】
    SpringBoot 接口数据加解密技巧
    微信小程序-人脸检测
  • 原文地址:https://blog.csdn.net/m0_63325890/article/details/125630102