当前位置: 首页 > news >正文

C生万物 | 十分钟带你学会位段相关知识

在这里插入图片描述

在这里插入图片描述
结构体相关知识可以先看看这篇文章 —— 链接

一、什么是位段

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

  1. 位段的成员必须是 intunsigned intsigned int
  2. 位段的成员名后边有一个冒号和一个数字
  • 在下面,我分别写了一个结构体和一个位段,注意看位段的写法和结构体有什么不同
//结构体
struct A {int a;int b;int c;int d;
};
//位段
struct B{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
  • 然后我们sizeof去计算一下这个结构体的大小
printf("结构体大小:%d\n", sizeof(struct A));
printf("位段大小:%d\n", sizeof(struct B));

可以看到,结构体的大小是16,位段是8,二者为何会存在区别呢?原因在于这个: 2吗?

  • 那根据位段后面的这些数字,我们可以初步去断定可能大小是这些数组的总和,再转换为字节的。计算一下可以知道为47b,在内存中1B = 8b,要存下这个47个比特位的话应该6个字节就够了,但是结果为什么是8呢?我们不得而知😐

在这里插入图片描述

学习了位段的相关知识后你就知道了

二、位段的内存分配

首先来科普一下位段的相关知识📖

  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节[int]或者1个字节 [char] 的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
  • 那从上面我们就可以提取出一些信息,知道了对于整型而言会开辟出4个字节的数据给到位段作为存放,那接下去呢我们就来分析一下这个位段
  • 仔细观察可以得知每个成员都是整型,那首先开辟出32个比特位
    • _a占了2个比特位,还剩下【30b】
    • _b占了5个比特位,还剩下【25b】
    • _c占了10个比特位,还剩下【15b】
    • _d占了30个比特位,但是剩下的【15b】不够用了,此时编译器会继续开辟出4B,也就是32b的空间来存放
  • 所以最后的结果就是4 + 4 = 8B
struct B{//4Byte - 32bitint _a : 2;		//30int _b : 5;		//25int _c : 10;	//15//4Byte - 32bitint _d : 30;//4 + 4 = 8
};

看了我上面的这样计算,你一定会有这些疑问

💬 第一次是32b用剩后的【15b】去哪儿了呢?

💬 _d使用的是【15b】+ 后面开辟出来的32b,还是只用到后面的32b呢?

💬 难道所有平台都是这样吗?有没有不一样的计算方法?

  • 上面是很多同学在课后提出来的疑问,关于这些,你在看完了我下面的分析后就会明白了👇

内存图分析位段分布

接下去我就通过对位段进行分析,然后观察内存分布来揭晓上面究竟是如何计算的。

为了方便期间,这里换一组位段,但是换汤不换药

struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main(void)
{struct S s = { 0 };s.a = 10;s.b = 12;s.c = 3;s.d = 4;return 0;
}
  • 首先来看一下存放这个位段需要的字节数。可以看到这个位段中的每个成员都是char类型的,所以编译器会首先为其分配一个字节的空间,然后随着变量的存入,最终是需要三个字节

在这里插入图片描述

然后我们来逐一分析一下💻

  • 刚才说了,这个位段在内存中需要开辟三个字节,这些变量要怎么存呢,首先看到变量a占了3个比特位,那是从左边的三位开始放还是右边的三位呢?总不可以从中间开始放吧!
  • 那我们假设一下,从右边往左边放,那么a放完后就是b,占4个比特位,但是放c的时候就放不下了,所以需要在开辟1个字节的空间,此时d再来放的话也放不下了,所以也要再开辟1个字节 ,最后也就需要3个字节的空间

在这里插入图片描述
详细分析如下】:

  • 接下去我们就根据main函数中对位段各变量的初始化,来看看位段在内存中的分布情况:a的初始值为10,不过这是十进制,转换为二进制形式的话就是[1010],转看位段这里a变量的是占了3位,所以会截断成010,将它放到第一个字节处的右边3个比特位处
  • 接下去是b,初始值为12,转换为二进制形式的话就是[1100],而b在内存中也刚好是占4个比特位的大小,刚好第一个字节处还可以放得过,所以继续顺位放置
  • 然后是c,初始值为3,转换为二进制形式的话就是11,但是c在内存中也占5个比特位的大小,所以要在前面做一个扩充便为[00011],但是第一个字节放不下了,上面放了【3】+【4】=【7】,只剩下1个比特位,那我们考虑再开一个字节的空间,为了保持连续性就直接把这个5个比特位的数据放到第二个字节的右边
  • 最后的是d,初始值为4,转换为二进制形式的话就是100,不过d在内存中也占4个比特位的大小,所以要在前面补上一个0,即为[0100],但是第二个字节也放不过了,只剩三个比特位了,所以我们考虑再开一个字节的空间,然后放这个d

上面只是我假设的编译器执行思维,不过真正是怎样的,我们还是要求证一下

  • 那要怎么求证呢?这个很简单,既然这些变量都是存放在位段中,那我们刚才都算出所存放的二进制形式了。对于内存中的地址一般我们看到都是十六进制,所以可以考虑把这些二进制4个为一组转换为十六进制看看
    • 01100010即为——>0x62
    • 00000011即为——>0x03
    • 00000100即为——>0x04
  • 而在内存中左边是低地址,右边是高地址,所以我们看到的应该是62 03 04 cc。来通过【内存】观察一下吧

可以看到,确实和我们分析得是一模一样✌
在这里插入图片描述


看完了上面这个,相信你对一开始的那个位段如何去进行求解的整个流程应该是非常清楚了,留给读者自己的分析观察🔍

三、位段的跨平台问题

接下去我们再来讲讲有关位段的跨平台的问题

  1. int 位段被当成有符号数还是无符号数是不确定的
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32)
    • 假设我们将位段中一个变量所占大小设置为30,即占30个比特位,那么它在32为机器上是没问题的,但是放到早期的16位机器上去的话,可能连编译都编不过,因为根本存放不下
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义
    • 刚才我分析的时候假设的是从右往左进行分配,但是呢这在其他平台上可能又是不一样的了
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的
    • 这也就是我们一开始纠结的【15】到底还用不用的问题,这里给出解答,还是不确定,取决于平台

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

  • 这可能还有的老铁不太理解,举个例子:假设结构体A中的这个变量a只可能有【0】【1】【2】【3】这四种取值,那么只需要2个比特位就可以表达这四个数字了,即【00】【01】【10】【11】,那我们便可以使用位段来是实现:2,但若是放在普通结构体中的话就只能是一个整型4个字节32个比特位的大小,这也就浪费了很多的空间
  • 同理,若是变量b也只有5种表示形式的话,5个比特位就够了,cd也是一样。那么这个时候位段就派上用场了,若是使用结构体的话就会浪费掉很多的空间。所以我们前面在看的时候,结构体所占的空间大小是16B,而位段只有8B

在这里插入图片描述

四、位段的应用

清楚了位段的相关知识和使用后,可能还是有同学比较迷惑这个位段到底是用来干嘛的,有什么实际应用场景吗?我们来看看

  • 比方说这里有个IP数据包,有学习过《计算机网络》相关知识的读者应该都很清楚【不了解可以看看网络层知识点汇总】,我们平常在网络上和别人互相聊天的时候,所发送的消息并不是直接在网络链路上进行传送的,而是会将其封装到一个数据包中,它叫做IP数据包,例如我们所发送的呵呵只是里面的一个数据部分,还存在其他很多的字段,这些字段都占有各自的字节数
  • 其实对于这些字节数来说,就是使用【位段】来实现,精准地控制好每个字段需要多少字节数,,就不会造成浪费的现象了

在这里插入图片描述

五、总结与提炼

最后来总结一下本文所学习的内容📖

  • 在本文中,我们首先讲到了位段的相关概念,知道了原来使用结构体还可以实现位段,不过在看了二者的大小后,却产生了疑惑,为什么位段所占的大小是这些呢?
  • 在清楚了位段在内容中的相关分布后,我带着读者一步步分析了位段中的成员数据到底是怎么一个个存放到内存中的,也通过VS中的【内存】验证观察了我们的分析结果,是正确的
  • 然后便说道了位段这个东西其实具备很大的不确定性,因为它存在跨平台的问题,在不同平台下实现的机制可能不同,所以就会导致最后的位段大小会不一致
  • 最后,也说道了位段的作用以及其实际的应用场景,让读者学以致用

以上就是本文要介绍的所有内容,感谢您的阅读,如果觉得有帮助的话,可以给个三连哦❤️❤️❤️

在这里插入图片描述
在这里插入图片描述

相关文章:

C生万物 | 十分钟带你学会位段相关知识

结构体相关知识可以先看看这篇文章 —— 链接 一、什么是位段 位段的声明和结构是类似的,有两个不同: 位段的成员必须是 int、unsigned int 或signed int位段的成员名后边有一个冒号和一个数字 在下面,我分别写了一个结构体和一个位段&…...

Spring Boot基础学习之(十):修改员工的信息

注意:spring boot专栏是一个新手项目,博文顺序则是功能实现的流程,如果有看不懂的内容可以到前面系列去了解。 本次项目所有能够使用的静态资源可以免费进行下载 静态资源 在本篇代码DAO层将通过Java文件去实现,在这里就不连接数…...

闭关十几天,我完成了我的毕业设计

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,也会涉及到服务端(Node.js) 📃个人状态: 在校大学生一枚,已拿多个前端 offer(…...

认识rust的项目管理工具--cargo

cargo 提供了一系列的工具,从项目的建立、构建到测试、运行直至部署,为 Rust 项目的管理提供尽可能完整的手段。不过,我们无需再手动安装,之前安装 Rust 的时候(用rustup或者vscode加插件的方式安装)&#…...

面试常问的Linux之 I/O 复用

I/O 复用 一、I/O的概念 在Linux系统中,I/O(输入/输出)指的是计算机系统的数据交换过程,包括从外部设备读取数据(输入)和将数据发送到外部设备(输出)。I/O操作是Linux系统中非常重要…...

MySQL-binlog+dump备份还原

目录 🍁binlog日志恢复 🍂binlog介绍 🍂Binlog的用途 🍂开启binary log功能 🍂配置binlog 🍁mysqldump 🍂数据库的导出 🍂数据库的导入 🍁mysqldumpbinlog 🦐…...

互联网络-单级互联网络

1.立方体单级网络 1.定义 立方体单级网络(cube)的名称来源于下图所示的三维立方体结构,如010只能连接到000、011、110,不能直接连接到对角线上的001、100、101、111。 2.例题 1.编号为0、1、2、3、4,…,15的16个处理器,用单级互联网络互联,用Cube0互联函数时,与第10…...

上海亚商投顾:沪指四连阳重回3300点 中字头个股再发力

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪大小指数今日走势分化,沪指低开后震荡反弹,创业板指盘中跌超1%。中字头个股再度发力&#x…...

LeetCode:150. 逆波兰表达式求值—栈

🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀算法专栏: 👉🏻123 一、🌱150. 逆波兰表达式求值 题目描述:给你一个字符串数组 token…...

C/C++每日一练(20230410) 二叉树专场(4)

目录 1. 二叉搜索树迭代器 🌟🌟🌟 2. 验证二叉搜索树 🌟🌟🌟 3. 不同的二叉搜索树 II 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专…...

策化整理1

概述: 本游戏是一款恐怖类解密游戏,以反应毒品的危害和反对家庭暴力为主题 在游戏中玩家扮演被困入梦境内的主人公,寻找逃出梦境的方法 本游戏故事大背景: 主人公的父亲是一名毒贩,在母亲发现父亲开始吸毒后选择与父亲…...

【服务通信自定义srv调用3----客户端的优化】

客户端的优化 服务通信自定义srv调用,客户端随意提交两个数,完成数的相加。也就是实现参数的动态提交: 1.格式:rosrun xxxx xxxx 12 34 2.节点执行时候,需要获取命令中的参数,并且组织进 request 代码中应…...

React跨域解决方案

一、跨域日志报错 我们由于项目需要经常会需要对不同域名、不同子域的网站接口发起请求,有时甚至是对于同一域名的不同端口发起请求,此时我们经常看到以下报错: Access to XMLHttpRequest at xxx from origin xxx has been blocked by COR…...

内存五区的概念,内存池技术的诞生。

首先提出一道经典的面试题来引出今天的主角: 进程的虚拟空间分布是什么样的,全局变量放在哪里? 在数据初始化之后,全局变量放在.data段 在数据未初始化时,全局变量放在.bss段 内存五区 进程虚拟内存主要分为五个部分…...

力扣:字符串中的第一个唯一字符(C++实现)

题目部分: 解题思路: 方案一: 首先认真审题的小伙伴们一定会发现就是题目给了提示只包含小写字母,也就是说我们的排查范围是小写的26个字母。为了怕有的友友们一时短路想不起来,我就其按照顺序列出来吧。 即&#x…...

攻防世界 favorite_number mfw、[BJDCTF2020]ZJCTF,不过如此

favorite_number 进入环境得到源码 <?php //php5.5.9 $stuff $_POST["stuff"]; $array [admin, user]; if($stuff $array && $stuff[0] ! admin) {$num $_POST["num"];if (preg_match("/^\d$/im",$num)){if (!preg_match("…...

SummingMergeTree

假设有这样⼀种查询需求&#xff1a;终端⽤户只需要查询数据的汇总结果&#xff0c;不关⼼明细数据&#xff0c;并且数据的汇总条件是预先明确的&#xff08;GROUP BY 条件明确&#xff0c;且不会随意改变&#xff09;。 对于这样的查询场景&#xff0c;在ClickHouse中如何解决…...

JUC并发编程基础篇第一章之进程/并发/异步的概念[理解基本概念]

1. 进程和线程的概念 进程: 系统正在运行的一个应用程序;程序一旦运行就是一个进程;进程是资源分配的最小单位 线程: 是进程的实际运行单位;一个人进程可以并发控制多个线程,每条线程并行执行不同的任务 区别: 进程基本上相互独立的;而线程存在于进程内&#xff0c;是进程…...

c语言—指针进阶

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

总结二分法

杨辉三角形&#xff08;快速查找唯一值,mid型) //二分法解//流程&#xff1a;最大列->起点行->2k--n之间究竟哪一行&#xff08;二分排列组合&#xff09;->找到行数就等差数列对应位置#include<stdio.h> #include<stdlib.h>//注意排列组合的规律是建立在…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...