结构体的简单介绍(4)——位段

news2024/11/18 22:47:11

目录

位段的概念:

位段的内存分配:

问题1:当开辟了内存后,内存中每个比特位从右向左使用?还是从左向右使用? 这个不确定。

问题2:当前面时候,剩余的空间不足下一个成员使用的时候,剩余的空间是否使用?这个不确定。

探究VS中的位段内存分布情况:

位段的跨平台问题:

注意事项:

热知识:



位段的概念:

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

  1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以 选择其他类型。
  2. 位段的成员名后边有⼀个冒号和⼀个数字。 

比如:

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


结构体:
struct A
{
 int _a;
 int _b;
 int _c;
 int _d;
};

以上代码分别是位段和结构体的对比,可以看出位段其实是基于结构体的。

位段的目的:

位段的出现,是为了节省空间的,而且位段中的位其实是比特位,或者说是二进制位。

比如:

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

上一串代码中,int_a:2; 中的2其实是表示两个比特位,也就是两位二进制。

而整个两个比特位的本质是:当我们给一个变量赋值时,这个数值在32位比特位中其实只需要两个比特位就能表达这个值是谁,例如我们本来是要给a赋值1,但1的二进制表达是01,只需要两个比特位就能表达1,而剩下的32位就会被浪费,造成空间的损失。

 以此类推,其他成员分别占据,5个比特位,10个比特位,30个比特位。

因为位段的目的是节省空间,所以整个位段的字节大小应该就是2+5+10+30=47个比特位。

按照一个字节等于八个比特位的运算原理,我们可以得到差不多6个字节。

和同样类型的成员,但并不是位段的结构体进行对比:

struct A
{
 int _a;
 int _b;
 int _c;
 int _d;
};

根据结构体的对齐规则,以上结构体需要在内存中占据16个字节,和位段相比起来,位段确实是节约了空间。

但是,位段真的如我们所算计的一样,是所有比特位相加而后在进行比特位和字节的换算吗?

答案并不是。

我们先后求以上两个代码,得到以下结果:

 没错,位段其实实际上所占据的字节是八个!

这里涉及了位段的内存分配问题。

 

位段的内存分配:

分配规则:

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

从规则得知,位段是根据成员的变量来进行开辟空间的,而不是将所有的比特位放置一个空间内,是先开辟对应类型的空间后再放置内容。

但是开辟空间后也会产生一系列的问题,这也是位段的不确定因素的原因。

问题1:当开辟了内存后,内存中每个比特位从右向左使用?还是从左向右使用? 这个不确定。

例如:

struct S
{
 char _a:3;
 char _b:4;
 char _c:5;
 char _d:4;
};

因为是char类型,占据一个字节,也就是八个比特位,所以我们率先开辟八个比特位空间。

 

那么问题来了,变量a是只能放置三个比特位再这一个字节中,但我们是从空间的右边往左边放,还是从字节的左边往右边放?

如果,从空间的右边往左边放,分别放了a(三个比特位)和b(四个比特位),那么剩下的那一个比特位(一个字节一共八个比特位),是否需要放置下一个变量的比特位?

问题2:当前面时候,剩余的空间不足下一个成员使用的时候,剩余的空间是否使用?这个不确定。

若我们下一个变量c(五个比特位)在开辟一个空间进行放置,后面的变量d(四个比特位)也是如此 ,(c所占据的字节中还剩下三个比特位,不够d所有的比特位)

那么这里一共就占据了三个字节,但答案真的是如此吗?

 

答案真是如此,就占据了三个字节。

所以我们得到了位段再VS编译器中,就是如此分配内存的! ——注!仅仅是VS编译器。 

同时我们也得到结论:位段其实也会浪费空间,但是相比于普通结构体而言,浪费的更少。

 

普通结构体:一共占据了四个字节。

struct S
{
 char _a;
 char _b;
 char _c;
 char _d;
};

所以最后还是节约了空间。

探究VS中的位段内存分布情况: 

struct S
{
 char a:3;
 char b:4;
 char c:5;
 char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

第一步, struct S s = {0};将结构体变量初始化为0

s.a =10 将10的二进制放到char a中,但是a只能放3个比特位,而10的二进制是1010,所以只能放三个比特位,从右到左截取三个进行存放。

第二步、b=12,b可以放四个比特位,12的二进制是1100,所以四个放入刚刚a放入的空间。

 

 第三步,该空间所剩下的比特位不够变量c(5个比特位)进行存放,所以另外开辟一共空间放入c的比特位。

而因为c是3,占据五个比特位,3的二进制是00011,所以存入五个进去。

第四步、同样d也需要开辟空间,且d需要四个比特位。d是4 二进制位是0100,存入新开辟的空间。

 

第五步、最后按照四个比特位(二进制位)一个十六进制位进行转化,最后再内存中的展示也是如此。

 

总结图:

 

以上都是VS编译器中出现的位段现象! 

 

位段的跨平台问题:

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

总结:

位段在不同的编译器不同的平台效果不一样, 所以建议在一定要需要节约内存的时候使用位段,若使用位段,只能不同的平台写不同的代码。

注意事项:

  • 位段的几个成员共有同一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。
  • 内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的。
  • 所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在一个变量中,然后赋值给位段的成员。 
struct A
{
 int _a : 2;
 int _b : 5;
 int _c : 10;
 int _d : 30;
};
int main()
{
 struct A sa = {0};
 scanf("%d", &sa._b);//这是错误的
 
 //正确的⽰范
 int b = 0;
 scanf("%d", &b);
 sa._b = b;
 return 0;
}

 

热知识:

  1. bit就是位,也叫比特位,是计算机表示数据最小的单位
  2. byte就是字节
  3. 1byte=8bit
  4. 1byte就是1B
  5. 一个字符=2字节
  6. 1KB=1024B

   1.字节就是Byte,也是B

   2.位就是bit也是b

   3.转换关系如下:

   1)1KB=1024B

   2) 1B= 8b

 

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

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

相关文章

1.使用turtle换一个五环2.设计这样一个程序:输入一个数字 判断它是不是一个质数

1.使用turtle换一个五环 import turtle turtle.pensize(15) turtle.penup() turtle.color(blue) turtle.goto(-150,-35) turtle.pendown() turtle.circle(60) turtle.penup() turtle.color(black) turtle.goto(0,-35) turtle.pendown() turtle.circle(60) turtle.penup() turtl…

ffplay源码解析-PacketQueue队列

包队列架构位置 对应结构体源码 MyAVPacketList typedef struct MyAVPacketList {AVPacket pkt; //解封装后的数据struct MyAVPacketList *next; //下一个节点int serial; //播放序列 } MyAVPacketList;PacketQueue typedef struct PacketQueue {MyAVPacketList …

LeetCode题解-让所有学生保持开心的分组方法数

⭐简单说两句⭐ 作者:后端小知识 CSDN个人主页:后端小知识 🔎GZH:后端小知识 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 亲爱的各位友友们,今天来给大家讲解一道力扣中等题&…

为什么要有override

多态一定会成功吗 因为逻辑是用户编写的,那么肯定会有遗漏的地方,那就要规则来限制。就比如多态,都知道条件之一是子类重写了父类的虚函数,但是如果子类没有严格遵守这个规则,就无法达到目的。就比如这个代码&#xf…

华清 c++ day7 9月14

#include <iostream> using namespace std;template<typename T> class myVector { private:T* arr;size_t size; //元素数量size_t max_size; //数组容量 public://构造函数myVector() :arr(nullptr), size(0), max_size(0) {}myVector(int size){if (size >…

ts 枚举类型原理及其应用详解

ts 枚举类型介绍 TypeScript的枚举类型是一种特殊的数据类型&#xff0c;它允许开发者为一组相关值定义一个共同的名称&#xff0c;使我们可以更清晰、更一致地使用这些值。 枚举类型在TypeScript中用enum关键字定义&#xff0c;每个枚举值默认都是数字类型&#xff0c;从0开…

Cannot access defaults field of Properties

今天打包maven项目时报错&#xff1a; 解决方案&#xff1a;在pom.xml中加入&#xff1a; <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.3.1…

C#---第22:Newtonsoft中json/array的解析、创建、SelectToken(获取指定values)方法

1.解析json & array (1)json解析 using Newtonsoft.Json.Linq;string json "{CPU: Intel,Drives: [DVD read/writer,500 gigabyte hard drive]}";JObject o JObject.Parse(json);Console.WriteLine(o.GetType()); Console.WriteLine(o.ToString()); Console.…

Windows配置python(anaconda+vscode方案)的主要步骤及注意事项

Windows配置python&#xff08;anacondavscode方案&#xff09;的主要步骤及注意事项 1、准备工作 anaconda&#xff0c;官网下载&#xff08;直接下载最新版&#xff09;vscode&#xff0c;官网下载 (官网直接下载有可能太慢&#xff0c;可以考虑在国内靠谱的网站上下载&…

GIS跟踪监管系统单元信息更新

GIS跟踪监管系统单元信息更新 单元信息更新。① 新增单元。② 编辑单元。③ 删除单元。物资查询&#xff08;1&#xff09;物资查询与展示。① 几何查询。• 单击查询&#xff1a;• 拉框查询&#xff1a;• 多边形查询&#xff1a;② 物资定位。• 多个物资定位&#xff1a; 单…

Python爬虫实战案例——第五例

文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff01;严禁将文中内容用于任何商业与非法用途&#xff0c;由此产生的一切后果与作者无关。若有侵权&#xff0c;请联系删除。 目标&#xff1a;采集三国杀官网的精美壁纸 地址&#xff1a;aHR0cHM6Ly93d3…

普中51-独立按键实验

独立按键实验 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时&#xff0c;电压信号 如下图所示&#xff1a; 由于机械点的弹性作用&#xff0c;按键开关在闭合时不会马上稳定的接通&#xff0c;在断开时 也不会一下子断开&#xff0c;因而在闭合和断开的瞬间均伴…

Windows11系统C盘用户文件夹下用户文件夹为中文,解决方案

说明&#xff1a; 1. 博主电脑为Windows11操作系统&#xff0c;亲测有效&#xff0c;修改后无任何影响&#xff0c;软件都可以正常运行&#xff01; 2. Windows10系统还不知道可不可行&#xff0c;因为Windows11的计算机管理中没有本地用户和组&#xff0c;博主在csdn上看到很…

华为云云耀云服务器L实例评测|redis漏洞回顾 MySQL数据安全解决 搭建主从集群MySQL 相关设置

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到过MySQL数据库被攻击的情况&#xff0c;数据丢失&#xff0c;还好我有几份备份&#xff0c;没有造成太大的损失&#xff1b;后来有发现Redis数据库被攻击的情况&#xff0c;加入了redis密…

R语言绘制热图

1、初步绘图 rm(listls())#clear Global Environment setwd(D:/Desktop/0000/code-main/热图)#设置工作路径#加载R包 library (pheatmap) #读取数据 df <- read.table(file"data.txt",sep"\t",row.names 1, headerT,check.namesFALSE) #查看前3行 hea…

STM32WB55开发(5)----调整射频功率

STM32WB55开发----5.调整射频功率 概述硬件准备视频教学样品申请选择芯片型号配置时钟源配置时钟树RTC时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙开启串口调试配置蓝牙参数设置工程信息工程文件设置Keil工程配置代码配置射频功率ACI_HAL_SET_TX_POW…

【微信小程序】外卖点餐效果展示

概述 外卖点餐效果展示&#xff0c;左右布局&#xff0c;快速点餐&#xff0c;商家信息展示等...程序是模仿人家的&#xff0c;所以界面没做什么调整&#xff0c;功能是没啥问题&#xff0c;可以正常使用... 详细 直接看效果图&#xff1a; 可以把这个点餐这个功能分为5部分…

docker总结

Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

SkyWalking9.5.0安装与SpringBoot性能链路监控

文章目录 1、下载安装1.1、安装Elasticsearch存储1.2、安装SkyWalking服务器端 2、监控微服务2.1、监控Spring Boot微服务2.1、监控Spring Cloud Gateway网关 Skywalking是分布式系统的应用程序性能监视工具&#xff0c;专为微服务&#xff0c;云原生架构和基于容器&#xff08…

Windows系统版本下载

1. msdn itellyou&#xff1a;MSDN, 我告诉你 - 做一个安静的工具站 (itellyou.cn) 2. MSDN系统库&#xff0d;致力于原版windows生态服务 (xitongku.com)