位段——(详细图解,保姆宗师级教程,包会,从基础概念到精通实战应用)

位段——大项目中结构体节省空间之手段

学习目标:

位段是什么
位段的内存分配
位段的平台局限性和应用

学习内容:

1.位段是什么

C++中的位段(Bit fields)是一种用于有效利用内存的特性,可以在结构体中定义成员变量的位数。它允许我们将多个成员变量打包到同一个内存单元中,从而节省内存空间。
在这里插入图片描述

通过位段,我们可以指定结构体成员变量的位数,以及它们在内存中的存储顺序。比如,假设我们想要定义一个结构体来表示一个日期,其中包括年、月、日。在不使用位段的情况下,每个成员变量通常都会占用一个整型(比如int)的大小,即4个字节。但是如果我们知道年份的范围在0到99之间,月份在1到12之间,日期在1到31之间,那么我们可以使用位段来减小结构体的大小。

struct Date {
  unsigned int year : 7;   // 使用7位存储年份(0-99)
  unsigned int month : 4;  // 使用4位存储月份(1-12)
  unsigned int day : 5;    // 使用5位存储日期(1-31)
};

int main() {
  Date d;
  d.year = 21;   // 存储的二进制为 010101,对应十进制为 21
  d.month = 10;  // 存储的二进制为 1010,对应十进制为 10
  d.day = 18;    // 存储的二进制为 10010,对应十进制为 18

  // 输出结果
  std::cout << "Year: " << d.year << std::endl;
  std::cout << "Month: " << d.month << std::endl;
  std::cout << "Day: " << d.day << std::endl;
  std::cout<<sizeof(Data)<<std::endl;
  return 0;
}

通过使用位段,我们可以将年份、月份和日期分别存储在一个字节内,总共只需要4个字节。这样可以有效地减小内存占用,但需要注意的是,位字段的位数必须小于或等于其所属成员变量类型大小的位数。此外,位字段还受限于平台和编译器的限制,对于不同的系统和编译器,行为可能会有所不同,因此在使用位段时要小心考虑跨平台和可移植性的问题

(不同编译器不同,VS2022是4个字节,也有些是3个字节)

2.位段的内存分配——泾渭分明,军阀规定地盘

在这里插入图片描述
在这里插入图片描述
举个例子,刚刚开始是a:3个比特,b:4个比特,c:5个比特,d:4个比特。

出庄,论功行赏,多劳多得
a 出3,b出4,c出5,d出4

abcd四个人规划地盘(绿色空间),划分好了就互不侵犯了。

什么意思?几个意思?我来告诉你——一个开始不是开了三个的绿色的空间)吗?
(一个char型1字节,8比特位)
因为人家a是先定义声明的并且规定3个比特,意思是a先占据了第一个绿色空间的后3个位,后三个0的空间是他的。

然后b来了,因为你第一个绿色空间还有5个比特位,而且你b只需要4位,所以b必须要占第一个绿色空间的4-7位。那么c来了之后他需要5个比特位,怎么办?第一个绿色空间只剩下了一个比特位,所以c必须去第二个绿色空间后5位。最后按规则d去了第三个绿色空间后四位。

abcd入驻军队,如果前面人数不够就补0

最后规定好自己的领地之后互不侵犯,赋值的时候先把全部变量搞成0,再把10赋值给a,因为10的二进制01010——但是你只有3个位置,所以你只能拿后三位010放进去
b=12的(二进制01100)——位置够可以放进去(位数不够就可以前面可以补0,这个无伤大雅,二进制前面补0只要不超过32位,不改变符号位都无所谓的)。c和d以此类推。

> 最终二进制化为十六进制——十六进制(书面显示更紧凑)

拓展——十六进制好处
十六进制在计算机中的处理更加高效。一方面,内存地址在计算机中通常采用字节(8个比特)为单位,而十六进制正好可以充分利用每个字节的8个比特,因为每个十六进制位对应4个比特。另一方面,在二进制和十六进制之间进行转换的计算也相对简单和高效,可以通过位移和逻辑运算等操作来实现

3.位段跨平台的局限性和应用

在这里插入图片描述
在这里插入图片描述
C++位段(Bit fields)可以用于在结构体或类中定义成员变量的位数,从而节省内存空间,并且可以更高效地处理特定的位操作。下面是一些C++位段的应用举例:

1.压缩数据结构:

用于存储非常数范围的数据,但是数据范围相对较小且可预测的情况。例如,可以使用位段来存储标志位、状态值或记录控制信息,从而减小数据结构的占用空间。

struct FlagBits {
  unsigned int isVisible : 1;  // 1位用于表示是否可见
  unsigned int isEditable : 1;  // 1位用于表示是否可编辑
  unsigned int isSelectable : 1;  // 1位用于表示是否可选择
  // 其他成员...
};

2.位操作和通信协议:

位段可以用于与底层硬件通信时,对数据进行位操作或者解析通信协议中的标识位。例如,可以使用位段来定义特定的位字段,以便对数据进行按位操作和提取。

struct Message {
  unsigned int messageType : 4;  // 4位用于表示消息类型
  unsigned int payload : 8;  // 8位用于表示有效载荷数据
  // 其他成员...
};

3原始数据序列化:

位段可以用于将数据序列化为二进制,并且可以更加紧凑地表示数据。例如,可以使用位段将结构体中的各个字段压缩为指定的位数,然后将其传输或存储。

struct SensorData {
  float temperature;  // 温度
  float humidity;  // 湿度
  unsigned int pressure : 14;  // 14位用于表示压力值(范围在0-16383)
  unsigned int status : 2;  // 2位用于表示状态信息
  // 其他成员...
};

后记:需要注意的是,位段的行为受编译器和平台的影响,可能在不同的系统和编译器上有所不同。此外,位段的使用也需要小心考虑可移植性和对齐问题,并且在处理位操作时需要注意位的顺序和对齐。因此,在使用位段时,建议查阅编译器文档以获取更详细的信息,并进行相应的测试和验证。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小卷同學

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值