【C语言】结构体实现位段

引言

对位段进行介绍,什么是位段,位段如何节省空间,位段的内存分布,位段存在的跨平台问题,及位段的应用。

  158c3f50b199454985017a51dbef9841.png               ✨ 猪巴戒:个人主页✨

               所属专栏:《C语言进阶》

        🎈跟着猪巴戒,一起学习C语言🎈

目录

引言

什么是位段?

位段的作用

位段是如何节省空间?位段的内存分配

位段的内存分配

位段的跨平台问题

        

位段的应用


什么是位段?

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

  1. 位段的成员必须是整形家族的类型
  2. 位段的成员名后面有一个冒号和一个数字。

冒号后面的数字表示的是这个变量将使用多大的内存(单位是比特位)。

int _n : 2 表示的是_n这个整形变量本来是4个字节(也就是32个比特位) ,但是现在要将它的内存缩减到2个比特位。

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

整形家族的介绍: 

整形类型不仅包括基本整形,还有短整形,长整形,双长整形,字符型和布尔型。

b4fd4b3056ff4971a99486c14624d9ff.png

类型字节数取值范围
int(整形)4

-2147483648~2147483647

short(短整型)2-32768~32767
long(长整型)4/8-2^31~(2^31-1)
long long(双长型)8-2^63~(2^63-1)
char1-2^7~(2^7-1)
bool11,0

         

位段的作用

位段的作用就是节省空间。当我们有一些成员的取值范围有限的时候,所需要的内存空间也不需要太多的空间。

比如说布尔类型

只需要表示真或者假,1表示真,0表示假。实际上布尔类型的变量只占有1个比特位,(1个字节代表着8个比特位),如果使用位段就可以帮助我们节省大量的空间。 

由此,位段所执行的大小不能大于这个变量类型本身的大小,不然就会报错。

546b96377921447d8eb222b0eac7aac5.png

        

位段是如何节省空间?位段的内存分配

下面是刚才给大家做示范的例子,我们现在看这个位段所占用的空间:

#include <stdio.h>
struct A
{int _n : 2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{printf("%d\n", sizeof(struct A));return 0;
}

9a87e8673b874b9aa753c39567832273.png

 _n,_b,_c,_d这四个变量的大小加在一起,一共是47个比特位,那就是需要6个字节的大小。

但是,我们发现struct A的大小不仅仅是6个字节,而是8个字节

这就说明位段中内存分布不仅仅是简单组合,顺序地一个紧挨着一个地存放。

        

位段的内存分配

  1. 位段的成员可以是整形家族的类型
  2. 位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的
  3. 位段涉及很多不确定因素,位段是不跨平台的,注意可移植的程序应该避免使用位段

2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的 

1.例子

下面位段的大小是8个字节

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

解析struct A的内存分布: 

还是拿这个例子给大家举例:

因为是位段都是int类型,所以这里位段的空间按照4个字节的方式开辟。

首先开辟4个字节来存放内存。

_n是2个比特位,_b是5个比特位,_c是10个比特位,一共是17个比特位

放在4个字节(32个比特位/一个整形大小)当中,剩下15个比特位。

是不足够放下_d(30个比特位),所以另外开辟一个整型大小(4个字节/32个比特位),将_d放进去。

_n,_b,_c放在前面的一个整形,_d放在后面的一个整形。

一共是两个整形,就是8个字节。

db256b441ab74c01b349aa96bcb98916.png

         

  2.例子

下面位段的大小是3个字节

#include <stdio.h>
struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};
int main()
{printf("%d\n", sizeof(struct S));struct S s = { 0 };s.a = 10;s.b = 12;s.c = 3;s.d = 4;return 0;
}

9160dc1ccd474560bbfe0423b787846a.png

         

 解析struct S位段的内存分布:

这个位段都是char 类型,所以这里位段的空间按照1个字节的方式开辟。

1.首先开辟1个字节(8个比特位),来存放数据

a是3个比特位,b是4个比特位,那么开辟的第一个字节就剩下1个比特位,是不足够存放5个比特位的c变量。

2.开辟下一个字节(8个比特位)存放数据

c是5个比特位,这个字节还剩下3个比特位,不足够存放4个比特位的d变量。

3.开辟下一个空间(8个比特位)存放数据

d是4个比特位,将d存放第三个字节中。

6b12e045b18f47c7bbf0c9e0e04dd112.png

         

 解析struct S的数据在内存中的具体分布:

//在位段中的成员被赋值后,观察内存分布	
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

struct S在内存中的分布其实是有所差异的,当位段中的成员被赋值后,我们就可以看到位段中的成员是如何分布的。

首先开辟一个字节后,

a=10的二进制数字是01010,位段:3个比特位,所以a的值放入内存中会被裁断,变成010.

b的值是12,位段:4个比特位,所以b存到内存中的值是1100.(数据是以二进制的形式存到内存)

a,b的存放方式如下图:a和b在第一个字节中的排列方式是从右到左的,也就是从高地址向低地址,在一个字节中优先排放高地址。

第二个字节开辟

c=3的二进制数字是11,位段:5个字节,不足5个字节用0来补充高位,也就是00011.

c的存放方式也是在这个字节中优先排放高地址处。

第三个字节开辟

d的值是4,二进制数字是100,位段:4个字节,高位用o来补充,也就是0100

d的存放方式也是在这个字节中优先排放高地址处。

ffe2ba31e0174983abe6ba386abfbb7c.png

所以位段struct S在内存中存放的数据是01100010 00000011 00000100

换算成十六进制数字就是 62 03 04

验证:

通过内存调试,观察内存窗口就可以看到

6ba1d2d19f724c15be105669fe1a14f7.png

         

位段的跨平台问题

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

总结: 

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

        

位段的应用

下图是⽹络协议中,IP数据包的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,能够实现想要的效果,也节省了空间,这样⽹络传输的数据报⼤⼩也会较⼩⼀些,对⽹络的畅通是有帮助的。
大量的数组经过位段的处理,可以将数据的内存缩小,是数据包的大小变小,数据包变小,网络的传输就会变得快速。
cbbe0daa46a44f1cb28b43085d50b671.png

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【从零开始学习JVM | 第六篇】快速了解 直接内存

前言&#xff1a; 当谈及Java虚拟机&#xff08;JVM&#xff09;的内存管理时&#xff0c;我们通常会想到堆内存和栈内存。然而&#xff0c;还有一种被称为"直接内存"的特殊内存区域&#xff0c;它在Java应用程序中起着重要的作用。直接内存提供了一种与Java堆内存和…

删除误提交的 git commit

背景描述 某次的意外 commit 中误将密码写到代码中并且 push 到了 remote repo 里面, 本文将围绕这个场景讨论如何弥补. 模拟误提交操作 在 Gitee 创建一个新的 Repo, clone 到本地 git clone https://gitee.com/lpwm/myrepo.git创建两个文件, commit 后 push 到 remote 作…

软件兼容性测试:保障多样化用户体验的重要功能

随着移动设备和操作系统的快速发展&#xff0c;软件兼容性测试变得越发重要。这项测试确保软件在不同平台、设备和环境下都能够正常运行&#xff0c;提供一致而稳定的用户体验。下面是软件兼容性测试中的一些关键功能&#xff1a; 1. 跨平台兼容性测试 在不同操作系统上运行的软…

C++写文件时主动刷新磁盘文件大小

一.效果 如下图所示,test.log是我正在写入的文件。 二.实现 #include <fstream> #include <io.h> #include <iostream> #include <stdio.h>class OfSteamImmediately : public std::ofstream { public:OfSteamImmediately(){}~OfSteamImmediately()…

js基础:简介、变量与数据类型、流程循环控制语句、数组及其api

JS基础&#xff1a;简介、变量与数据类型、流程循环控制语句、数组及其api 一、简介 1、js概述 tip&#xff1a;JavaScript是什么&#xff1f; 有什么作用&#xff1f; JavaScript&#xff08;简称JS&#xff09;是一种轻量级的、解释性的编程语言&#xff0c;主要用于在网页…

洛谷 P8802 [蓝桥杯 2022 国 B] 出差

文章目录 [蓝桥杯 2022 国 B] 出差题目链接题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 思路解析CODE [蓝桥杯 2022 国 B] 出差 题目链接 https://www.luogu.com.cn/problem/P8802 题目描述 A \mathrm{A} A 国有 N N N 个城市&#xff0c;编号为 1 … N …

在vscode下将ipynb文件转成markdown(.md文件)的方法

在vscode下将ipynb文件转成markdown&#xff08;.md文件&#xff09;的方法 写在最前面安装nbconvert工具vscode界面 or cmd终端基本命令将ipynb文件转换成md文件 总结 写在最前面 VSCode作为一款强大的代码编辑器&#xff0c;提供了广泛的功能。它支持多种文件格式的编辑和查…

deepface:实现人脸的识别和分析

deepface介绍 deepface能够实现的功能 人脸检测&#xff1a;deepface 可以在图像中检测出人脸的位置&#xff0c;为后续的人脸识别任务提供基础。 人脸对齐&#xff1a;为了提高识别准确性&#xff0c;deepface 会将检测到的人脸进行对齐操作&#xff0c;消除姿态、光照和表…

InnoDB在SQL查询中的关键功能和优化策略

文章目录 前言存储引擎介绍存储引擎是干嘛的InnoDB的体系结构 InnoDB的查询操作InnoDB的查询原理引入 Buffer Pool引入数据页Buffer Pool 的结构数据页的加载Buffer Pool 的管理Buffer Pool 的优化 总结 前言 通过上篇文章《MySQL的体系结构与SQL的执行流程》了解了SQL语句的执…

css 表示具有特定类或者其他属性的某种标签类型的元素

需求 通过 css 选择器获取某种标签&#xff08;如&#xff1a;div、input 等&#xff09;具有某个属性&#xff08;如&#xff1a;class、id 等&#xff09;的元素&#xff0c;从而修改其样式。 代码 通过 [标签].[属性] 的方式来获取 <div class"test">&l…

Spring-Boot---配置文件

文章目录 配置文件的作用配置文件的格式PropertiesProperties基本语法读取Properties配置文件 ymlyml基本语法读取yml配置文件 Properties VS Yml 配置文件的作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;具有非常重要的作用。比如&#xff1a; 数据库的…

如何解决MAC卸载软件后图标还在的问题

今天卸载photoshop突然遇到一个问题&#xff0c;程序卸载完成后居然还有一大堆的图标删不掉&#xff0c;果断找法子&#xff0c;下面就是我应用到的方法&#xff0c;希望对你有所帮助&#xff0c;只能是photoshop太流氓啊。。。 方法一&#xff1a; 使用命令(Command) 空格键…

Vue3中的defineModel

目录 一、vue3的defineModel介绍 二、defineModel使用 &#xff08;1&#xff09;在vite.config.js中开启 &#xff08;2&#xff09;子组件 &#xff08;3&#xff09;父组件 一、vue3的defineModel介绍 为什么要使用到defineModel呢&#xff1f;这里有这样一种场景&…

Java的NIO工作机制

文章目录 1. 问题引入2. NIO的工作方式3. Buffer的工作方式4. NIO数据访问方式 1. 问题引入 在网络通信中&#xff0c;当连接已经建立成功&#xff0c;服务端和客户端都会拥有一个Socket实例&#xff0c;每个Socket实例都有一个InputStream和OutputStream&#xff0c;并通过这…

Mirrors and reflections for VR

专为虚拟现实而建,但也非常适合非虚拟现实桌面和移动项目 这是URP管道,从Unity2019.4.16一直测试到2023年。 完全工作场景预览,轻松修改着色器材质。着色器支持折射,可以制作很酷的效果。 镜子/反射可以互相反射,而不仅仅是2...想象一下一个电梯,3面镜子都互相反射,直到…

【PTA刷题】 求子串(代码+详解)

【PTA刷题】 求子串(代码详解) 题目 请编写函数&#xff0c;求子串。 函数原型 char* StrMid(char *dst, const char *src, int idx, int len);说明&#xff1a;函数取源串 src 下标 idx 处开始的 len 个字符&#xff0c;保存到目的串 dst 中&#xff0c;函数值为 dst。若 len…

算法-02-排序-冒泡插入选择排序

一般最经典的、最常用的&#xff1a;冒泡排序、插入排序、选择排序、归并排序、快速排序、计数排序、基数排序、桶排序。那么我们如何分析一个"排序算法"呢&#xff1f; 1-分析排序算法要点 时间复杂度&#xff1a;具体是指最好情况、最坏情况、平均情况下的时间复杂…

现代雷达车载应用——第2章 汽车雷达系统原理 2.1节

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.1 基本雷达功能 雷达系统通过天线或天线阵列向空间辐射电磁能量。辐射的电磁能量“照亮”周围的目标。“被照亮”的目标拦截一些辐射能量&#xff0…

如何搭建eureka-server

在Spring Cloud项目的pom文件中添加eureka-server的starter依赖坐标 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://ma…

每日一道c语言

任务描述 题目描述:输入10个互不相同的整数并保存在数组中&#xff0c;找到该最大元素并删除它&#xff0c;输出删除后的数组 相关知识&#xff08;略&#xff09; 编程要求 请仔细阅读右侧代码&#xff0c;结合相关知识&#xff0c;在Begin-End区域内进行代码补充&#xf…