【详解】C语言冷门知识点之--位段

news2024/11/24 2:01:35

文章目录

  • 一, 位段的解释
  • 二, 位段的声明和使用
    • 位段的声明:
    • 位段的使用:
  • 三,位段的空间大小计算
    • 第一个例子:
    • 第二个例子:
    • 注意:
  • 四, 位段的内存分配
  • 五,位段的跨平台问题
  • 六, 位段的应用

一, 位段的解释

下面是维基百科对位段的解释:

  位段(或称“位域”,Bit field)为一种数据结构,可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作。这种数据结构的好处:

  • 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要。
  • 位段可以很方便的访问一个整数值的部分内容从而可以简化程序源代码。

  而位域这种数据结构的缺点在于,其内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的

二, 位段的声明和使用

  • 虽然位段可以决定用多少位来储存数据,但是切不可认为位段就是可以自定义一个数据类型。位段是依赖结构体来实现的,我们可以认为位段是可以将一个盒子里面格子自定义大小。
    在这里插入图片描述

位段的声明:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

需要注意的是:

  • 这里面的数字代表的不是字节,是比特(bit)
  • 位段成员的类型只能是整型家族的,例如:int, unsigned int, signed int, char。

位段的使用:

int main()
{
	struct A a;
	a._a = 2;
	a._b = 3;
	a._c = 5;
	a._d = 10;
	return 0;
}

相当于实例化后的a里面的不同大小的内存里放入了数据。

三,位段的空间大小计算

因为不同平台上的规则都是不太一样的,计算出来的结果也会有些许差异,以下使用vs2022的x64环境下运行的
例如:

第一个例子:

#include <stdio.h>
struct A
{
	int _a : 2;//二进制位
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

int main()
{
	printf("%d", sizeof(struct A));
	return 0;
}

上面代码的输出结果是8

  • 声明类型是int类型的,所以一开始先开辟4个字节的内存,也就是32bit。
  • _a用掉了2bit,还剩下30bit。
  • _b用掉了5bit,还剩下25bit。
  • _c用掉了10bit,还剩下15bit。
  • _d需要30bit的空间,但是预先开辟的空间只剩下15bit,所以我们还需要再开辟一个int大小的空间,之前剩下的15bit的空间选择不使用,_d的30bit全放在第二个空间内。
  • 结果为8

第二个例子:

#include <stdio.h>
struct B
{
	int _a : 30;//二进制位
	int _b : 4;
	int _d : 32;
};

int main()
{
	printf("%d", sizeof(struct B));
	return 0;
}
  • 声明类型是int类型的,所以一开始先开辟4个字节的内存,也就是32bit。
  • _a用掉了30bit,还剩下2bit。
  • 由于只剩下2bit,_b需要4bit,所以舍弃2bit,再开辟一个32bit空间, _b用掉了4bit,还剩下28bit。
  • 由于只剩下28bit,_d需要32bit,所以舍弃28bit,再开辟一个32bit空间,_d用掉了32bit
  • 总共开辟了3次int类型的空间,所以结果为12

注意:

  大家有没有发现,我们在声明位段的时候,如果定义的是int,那么冒号后面跟上的数字不能超过32,如果定义的是char,那么冒号后面跟上的数字不能超过8。如果超过以后,就会报出以下错误:
在这里插入图片描述

  其实根据内存对齐原则,如果超出以后,处理器就需要访问两次才能完整的得到数据。所以在定义的时候,应该避免超出应有的内存大小。

四, 位段的内存分配

  • 位段分配的内存中的比特位是从左向右使用的,还是从右向左使用的呢?
  • 如何证明内存分配剩余的比特位不够使用时,是继续使用还是浪费掉呢?

接下来我们分析:
用例代码:

#include <stdio.h>
struct A
{
	char _a : 3;
	char _b : 4;
	char _c : 5;
	char _d : 4;
};
int main()
{
	struct A a = {0};
	a._a = 10;
	a._b = 12;
	a._c = 3;
	a._d = 4;
	return 0;
}

我们假设:位段分配的内存中的比特位是从右向左使用的,分配剩余的比特位不够使用时,浪费掉剩余内存。
则:

  • 我们先定义位段,如下图:
    在这里插入图片描述
  • 执行程序:a._a = 10; 10的二进制为1010,放入_a中,由于_a只有3bit,需要截断,所以舍弃最高位1,放入010:

在这里插入图片描述

  • 执行程序:a._b = 12;,12的二进制为1100,刚好可以放入,如下图:
    在这里插入图片描述
  • 执行程序:a._c = 3;,3的二进制为11,由于_c有5bit,高位添0,放入00011,如下图:
    在这里插入图片描述
  • 执行程序:a._d = 4;,4的二进制为100,放入0100,如下图:
    在这里插入图片描述
  • 程序就基本执行完了,那么内存中是什么样的呢?根据上面分析,我们一开始给结构体初始化为0,我们可以得到:
    在这里插入图片描述
      由于机器是小端存储,所以内存上应该是:62 03 04.
    经过调试,可以看到:
    在这里插入图片描述

  以上也证明了, 在VS2022上,位段分配的内存中的比特位是从右向左使用的,分配剩余的比特位不够使用时,浪费掉剩余内存,重新开辟新的空间。

当然,不同平台得到的结果也可能会不同,这正是位段的缺点,可移植性差,接下来我们看看位段的跨平台问题。

五,位段的跨平台问题

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题)。
  3. 位段中的成员在内存中从左向右分配还是从右向左分配的标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳打一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

六, 位段的应用

位段由于跨平台的问题,真正的用途的其中一个是计网的IP数据报:
在这里插入图片描述

  😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

@Autowired 到底是怎么把变量注入进来的?

文章目录 1. Bean 的创建2. populateBean3. postProcessProperties3.1 findAutowiringMetadata3.2 inject3.3 doResolveDependency 4. 时序图 在 Spring 容器中&#xff0c;当我们想给某一个属性注入值的时候&#xff0c;有多种不同的方式&#xff0c;例如可以通过构造器注入、…

C++ string类型的基本使用方法

目录 1.定义和初始化string对象 2.string对象上的常用操作 在C中string是用来处理可变长字符串的&#xff0c;是C标准库中提供的类型&#xff0c;使用起来十分方便。同时C也支持C语言的字符数组来表示字符串。使用时记得包含string头文件。 1.定义和初始化string对象&#xf…

讨论下相亲交友小程序介绍红娘系统搭建的功能有哪些

首页内容 同城会员&#xff0c;VIP会员&#xff0c;线下会员&#xff0c;热文推荐&#xff0c;恋爱话术&#xff0c;爱情故事&#xff0c;恋爱宝典&#xff0c;相亲宝典&#xff0c;浪漫约会&#xff0c;相亲活动&#xff0c;地区、年龄筛选&#xff0c;用户动态&#xff0c;用…

(简单)剑指Offer || 056. 二叉搜索树中两个节点的和 Java

方法一&#xff1a;深度优先搜索哈希表 使用深度优先搜索的方式遍历整棵树&#xff0c;用哈希表记录遍历过的节点的值 对于一个值为x的节点&#xff0c;检查哈希表中是否存在k-x即可。如果存在对应的元素&#xff0c;那么我们就可以在该树上找到两个节点的和为k&#xff1b;否…

Idea 修改默认 Maven 为自己的

每次我们打开新项目时,都要去配置一遍 maven,很麻烦,其实可以去修改 idea 里面默认的 maven 配置,这样后面不管是打开新项目还是老项目,就都是用的自己的 maven 了. 1.文件->新项目设置->新项目的设置 File->Other Settings -> Settings for New Project 2.然后和…

【Unity开发必备】100多个 Unity 学习网址 资源 收藏整理大全【持续更新】

Unity 相关网站整理大全 众所周知&#xff0c;工欲善其事必先利其器&#xff0c;有一个好的工具可以让我们事半功倍&#xff0c;有一个好用的网站更是如此&#xff01; 但是好用的网站真的太多了&#xff0c;收藏夹都满满的(但是几乎没打开用过&#x1f601;)。 所以本文是对…

eclipse : sun.misc.BASE64Encoder找不到jar包的解决方法

sun.misc.BASE64Encoder找不到jar包 比较好的解决办法 按顺序依次操作&#xff1a; Windows -> Preferences -> Java -> Compiler -> Errors/Warnings。再按照顺序依次&#xff1a; Deprecated and trstricted API -> Forbidden reference (access rules): -&g…

量子力学的实验验证:双缝实验和贝尔不等式

亲爱的读者&#xff0c; 欢迎回到我们的量子力学系列文章。在前几篇文章中&#xff0c;我们介绍了量子力学的起源、基本概念&#xff0c;以及叠加态、超级定位和量子纠缠等奇特现象。今天&#xff0c;我们将深入探讨量子力学的实验验证&#xff0c;重点介绍双缝实验和贝尔不等…

Android自定义圆环进度条/刻度仪表盘(单环单点带进度动画)

效果图: 1.自定义SleepDashBoardView /*** 睡眠刻度仪表盘*/ public class SleepDashBoardView extends View {private static final float START_ANGLE 135f;private static final float MAX_ANGLE 270f;private float progress 0;private float centerX;private float ce…

ValueError: check_hostname requires server_hostname怎么解决?

背景: 想使用pip安装某一个包。结果报错如上图绿框所示。 解决方法&#xff1a; 把代理&#xff08;梯子&#xff09;关掉就行了。

数据库应用:MySQL事务、存储引擎

目录 一、理论 1.事务 2.MySQL 存储引擎 二、实验 1.事务隔离级别 2.事务控制语句 三、总结 一、理论 1.事务 &#xff08;1&#xff09;概念 ① 事务是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个整体一起向系…

XUbuntu22.04之解决ThindPad P15V风扇狂转的问题(一百八十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

深度学习标量、向量、矩阵、张量之间的区别与联系

文章目录 前言1、张量**注意**&#xff1a; 2、**标量** (scalar)&#xff1a;0阶的张量&#xff0c;0个轴&#xff0c;一个单独的数(整数或实数)&#xff1b;3、**向量**(vector)&#xff1a;1阶的张量&#xff0c;也叫矢量&#xff0c;1个轴&#xff0c;一个数组&#xff1b;…

elasticsearch学习入门+实战

学习链接1 基础概念 官网学习&#xff1a;地址 基本命令 PS&#xff1a;使用Apifox测试 查询所有索引库 添加索引库 添加时&#xff0c;加入分词器 添加时&#xff0c;加入记录属性值 查询获取索引库 删除索引库 添加文档 必须要在添加文档值的时候用【_doc】&a…

如何建立统一的自动化测试平台?

前面的文章中我们为大家介绍了中通科技自动化测试当时正在面临的一些困境。第一个是自动化测试框架太多&#xff0c;测试工程师在选择框架和脚本语言的时候很难统一&#xff0c;脚本编写门槛高。第二个是运行脚本的平台不统一&#xff0c;脚本运行时不够稳定。第三个是不同的Je…

TDengine数据建模

文章目录 1 引言2 数据建模3 数据建模的步骤4 创建库5 创建超级表实例 1 引言 工业互联网中有大量的时序数据需要存储和处理&#xff0c;tdengine是一个开源的、国产的、云原生时序数据库&#xff0c;tdengine不是基于其他第三方开源软件高级封装&#xff0c;是涛思数据完全自…

Java如何避免“重复代码”

一 前言 软件工程师和码农最大的区别就是平时写代码时习惯问题&#xff0c;码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。 业务同学抱怨业务开发没有技术含量&#xff0c;用不到设计模式、Java 高级特性、OOP&#xff0c;平时写代码都在堆 CRUD&…

2022-2023年项目总结

1.健康监护仪&#xff08;WPF-用时两周&#xff09; 通讯协议比较复杂&#xff0c;但展示要求不高&#xff0c;时间都花在了后台代码上&#xff0c;不过调试过程比较顺利&#xff0c;总体用时不长&#xff0c;下图&#xff1a;假数据演示 2.AI内窥镜&#xff08;WPF-用时2月&a…

Windows10 PDF文件删不掉 解决办法

在使用Windows10系统时&#xff0c;有时会遇到文件删不掉的情况&#xff0c;本文提供一种删除文件方法&#xff0c;在自己计算机尝试成功。 适用环境&#xff1a;Windows10下名字太长的PDF文件。 原因&#xff1a;文件名超过255个字符长度&#xff0c;导致windows10 系统无法…

REMB-接收端最大接收码率评估

draft-alvestrand-rmcat-remb-03 接收方带宽估计的RTCP消息 REMB_fanyamin的博客-CSDN博客 webrtc中的码率控制_webrtc设置码率_linux_vae的博客-CSDN博客 参考&#xff1a; Walter: WebRTC 拥塞控制之 REMB - 接收方带宽估计 - 简书 WebRTC基于TransportCC和Trendline Fil…