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

C语言(数据存储)

        Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,欢迎欢迎~~     

                                                💥个人主页:小羊在奋斗

                                                💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为一些学友们展示一下我的学习过程及理解。文笔、排版拙劣,望见谅。 

                                1、大小端字节序和字节序判断

                                2、浮点数在内存中的存储

                                                2.1浮点数存的过程

                                                2.2浮点数取的过程

1、大小端字节序和字节序判断

        在 C语言(操作符)1 中,我们介绍了整数在内存中的存储,但是我们只介绍了整数的存储形式,并没有介绍整数是如何存储的,那本节我们就来探讨一下整数在内存中究竟是怎么存储的。

        当我们想把0x11223344这个数存到一个整型变量a中时,因为整型数据的大小是4个字节,以字节为单位存储,那么11占一个字节,22占一个字节,33占一个字节,44占一个字节,假设从低地址向高地址存储,那先存11还是先存44就是一个问题。其实超过一个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为大端字节序存储和小端字节序存储。

        也就是说,大端字节序存储是地址由低到高依次存高位,小端字节序存储是地址由低到高依次存低位。

         我们之前可能会疑惑VS中整数在内存中为什么是反着存的,那这里就给了我们解释,VS所在的当前计算机系统使用的是小端字节序存储,而大多数计算机架构使用的都是小端字节序存储。

        如果我们想知道当前的机器使用的是哪种存储方式,可以写一个简单的判断小程序来实现。当我们在一个整型变量中存一个整数1时,如果当前机器是大端字节序存储,那么它存的就是         00 00 00 01,如果当前机器是小端字节序存储,那么它存的就是 01 00 00 00。既然如此,我们只需要将这个整型变量最小字节中的数据拿出来,看这个最小字节单元中存的数是0还是1,如果是0就是大端字节序存储,反之则为小端字节序存储。

        了解了大小端存储,我们来做一些练习加深理解。

        练习1 

        上面代码的输出结果是什么呢?(其实我们在C语言(操作符)2中的表达式求值部分已经学习过)我们来分析一下:

        我们想将整数-1存入一个字符型变量a中,整型和字符型不兼容,通过C语言(操作符)2的学习我们知道要发生截断,所以只将-1的补码的后8位存到a中,我们又用%d(打印有符号整型)打印字符型变量a,那%d就认为它打印的数是整型,a不是整型所以要发生整型提升,a是char(signed char)类型,整型提升高位补符号位,补完后还是32个1,取反加一得原码又变为了-1,最终结果就打印出了-1,因为在VS中char和signed char是一样的,所以打印b也就同样的道理。

        而我们将整数-1存入一个无符号字符型变量c中,截断只存入-1的补码的后8位,用%d打印需要整型提升,而c是无符号字符型,整型提升高位补0,补完后用%d打印时%d看它就是一个比较大的正数,原反补相同,00000000000000000000000011111111就是255。

        练习2 

        将整数-128(补码:11111111111111111111111110000000)存入(signed)char类型a中,截断后a中存的是10000000,用%u(打印无符号整数)打印需要整型提升,a为signed char所以高位补符号位,补完就是11111111111111111111111110000000,目前还是补码,但是在%u眼中无符号整形原反补相同,所以%u再以原码打印出来就是4294967168。

        将a改为128,结果还是一样的,因为它们截断的结果是一样的。

        至于为什么对a存-128还是128结果是一样的,这里再做一个解释:

        我们很早就知道,(signed)char类型的取值范围是:-128~127 ,但是为什么是这个范围并没有解释。char类型占一个字节也就是8个比特位,最高位当做符号位来看待,就剩下了7位存0、1值。

        在C语言(操作符)2中,我们还画了这样一个图,并做了相应解释。

        127+1在数学上是128,但在char类型中就是-128,因为char类型最大的正数就是127,所以给char类型存128和-128是一样的。其他的类型都是这样的道理。

        练习3 

 

        创建一个字符数组大小1000,向数组中存入-1、-2、-3..,然后strlen求字符数组a的长度。我们知道strlen是求字符串的长度,统计的是\0之前的字符个数,那看来意思就是让我们找字符‘\0’了又因为a是字符数组所以-1、-2、..、-127、-128、127、126、...、2、1、0,0在字符眼中就是\0,所以求的是-1~0的长度,是255。

 

        练习4 

        unsigned char的范围是0~255,所以上面的代码给我们的感觉就是打印255个hello world,但事实真是如此吗?当我们运行起来就会发现程序陷入了死循环。这是因为当i加到256时虽然此时不满足循环了,但是这时候的256只是数学上的256,而在unsigned char眼中255+1就变成了0,所以循环继续。

        上面这个代码也是如此,当i为0时,0-1就变成了2^32-1,因为在unsigned int的世界里没有负数,所以程序陷入了死循环。

        练习5

        创建一个整型数组大小4,&a取出整个数组的地址再+1跳过整个数组指向数组末尾,此时指针(地址)的类型是int (*) [4],再强转为 int * 类型的指针赋给ptr1,ptr1[-1]( *(ptr -1) )就是int *类型的指针-1向后推4个字节指向数组最后一个元素4,再解引用用%x(打印16进制)打印出来就是4。

        数组名a表示数组首元素的地址,强转为int类型的整数再+1,再强转为int *类型的指针,最终的结果就是数组首元素的地址+1(整数+1),注意ptr2是一个整型类型的指针,所以它访问的是4个字节的地址。

 

        我们又知道小端字节序是反着存的,所以ptr2指向的数值就是02 00 00 00,打印出来就是2000000。

        如果我们想把代表16进制的0x也打印出来,可以在%的后面加上#。

2、浮点数在内存中的存储

        2.1浮点数存的过程

        浮点数和整数在内存中的存储有什么区别吗?

        如果用我们学到的整数存储的方法来解读上面的代码,打印出来的结果应该就是9、9.000000、9、9.000000。

        但结果并不是这样,通过观察我们发现,只有当n是整数9时用%d打印的结果和当n是浮点数9.0时用%f打印的结果是我们预料中的,所以可以肯定的是整数和浮点数在内存中的存储是不一样的。

        那浮点数在内存中是怎么存的呢?根据 IEEE 754规定,任意一个二进制浮点数V可以表示为这样的形式:V=(-1)^S*M*2^E。(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。M表示有效数字,M是大于等于1小于2的。2^E表示指数位。

        比如十进制的5.5,写成二进制就是101.1,转化的方法是按位权来转化,小数点前面的位权是2的1次方、2的2次方、2的3次方....,小数点后面的位权是2的-1次方、2的-2次方、2的-3次方......。十进制的5.5二进制表示101.1用科学计数法表示就是1.011*2^2,又因为5.5是正数,所以用IEEE 754标准表示就是:(-1)^0*1.011*2^2。其中的S=0,M=1.011,E=2。

        任何一个浮点数都可以用S、M、E这三个值来表示,所以浮点数的存储,存储的就是S、M、E 相关的值

        IEEE 754规定:

        对于32位的浮点数(float),最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。

         对于64位的浮点数(double),最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M。

        IEEE 754对有效数字M和指数E还有一些特别规定。 

        前面说过,1<=M<=2,所以M总是1.xxxxx,IEEE 754规定,在计算机内部保存M时,默认这个数的第一位是1,因此1可以舍去,只保存小数点后面的xxxxx,读取的时候再把第一位的1加上就行。这样做的目的是节省1位有效数字,使存储的精度更高。 

        E作为一个无符号整数,如果E为8位,它的取值范围是0~255;如果E为11位,它的取值范围是0~2047。但是在科学计数法中指数有可能是负数,所以 IEEE 754规定,存入内部的E的真实值必须再加上一个中间数,对8位的E这个中间数是127;对11位的E这个数是1023。比如2^10的E是10,保存成32位的浮点数时,必须保存成137,即10001001。我们也不用担心加上这个中间数后E的值还不能为正数,因为当E非常小时已经无限接近于0了,而float和double也是有精度限度的。

        比如float类型的5.5在内存中的存储就是:

 

        本计算机系统采用的是小端字节序存储。 

        2.2浮点数取的过程

        指数E从内存中取出的过程可分为三种情况:

        E不全为0或不全为1(常规情况)

        指数E的计算值减去127或1023得到真实值,再将有效数字M前加上第一位的1。

        E全为0(罕见)

        这时,浮点数的指数E等于1-127或1-1023即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxx的小数。这样做是为了表示+-0,以及无限接近于0的极小的数字。

       E全为1(罕见)

        这时,E的真实值为255-127=128,这又是一个极大的数,大到我们无法想象,所以就不去讨论它了。

        了解清楚了浮点数在内存中的存取后,我们再来分析一下前面的那个代码。

        创建一个整型变量n赋值为9,用%d打印时就按常规打印出整数9。我们再取出n的地址将其强转为float *类型的指针再赋给pfloat,再解引用pfloat用%f打印,9在内存中的补码是:

00000000000000000000000000001001,而pfloat是float *类型的指针,所以pfloat就认为它指向的数是一个浮点数,就会按浮点数存取的规则来读取,在pfloat眼中整数9的补码是这个样子:

 

        S=0,E为全0,那这个值就是一个极小的正数,无限接近于0,而float只能打印小数点后6位,所以打印的结果应该就是0.000000。

        而将9.0存到float *类型的地址中时,9.0用二进制表示为:1001.0,根据 IEEE 754 规定,S=0,M=1.001,E=3,那在内存中的存储就应该是下面这个样子的:

        用%d打印时%d就认为这是一个很大的正数 ,原反补相同。而用%f打印就是正常的9.000000。

 

 

        本节内容并不需要我们死记硬背,只需要知道整数和浮点数在底层是怎么存取的,又有什么差异,当某天我们错用格式符打印不同类型的值时,我们要知道是怎么回事,要会分析,为什么会输出这个值,这个值是随机的还是有它的道理的就行。

        只要我们遵守规则,有符号整数就用%d打印,无符号整数就用%u打印,float类型就用%f打印,double类型就用%lf打印,size_t类型就用%zd打印……就行。

         如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。  

相关文章:

C语言(数据存储)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸各位能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎~~ &#x1f4a5;个人主页&#xff1a;小羊在奋斗 &#x1f4a5;所属专栏&#xff1a;C语言 本系列文章为个人学习笔记&#xff0c;在这里撰写成文一…...

Linux shell编程学习笔记56:date命令——显示或设置系统时间与日期

0 前言 2024年的网络安全检查又开始了&#xff0c;对于使用基于Linux的国产电脑&#xff0c;我们可以编写一个脚本来收集系统的有关信息。在收集的信息中&#xff0c;应该有一条是搜索信息的时间。 1. date命令 的功能、格式和选项说明 我们可以使用命令 date --help 来查看 d…...

Realsense的一些事情

Realsense的一些事情 librealsense的安装 官网教程&#xff1a; apt 安装教程&#xff1a; https://github.com/IntelRealSense/librealsense/blob/master/doc/distribution_linux.md自行clone并编译教程&#xff1a; https://github.com/IntelRealSense/librealsense/blo…...

CISCN 2023 初赛 被加密的生产流量

题目附件给了 modbus.pcap 存在多个协议 但是这道题多半是 考 modbus 会发现 每次的 Query 末尾的两个字符 存在规律 猜测是base家族 可以尝试提取流量中的数据 其中Word Count字段中的22871 是10进制转16进制在转ascii字符串 先提取 过滤器判断字段 tshark -r modbus.pcap …...

初识C语言第三十天——设计三子棋游戏

目录 一.设计游戏框架 1.打印游戏菜单 2.输入选择判断&#xff08;玩游戏/游戏结束/输入错误重新输入&#xff09; 二、玩游戏过程设计 1.设计棋格存放棋子——二维数组 2.初始化棋盘——初始化为空格 3.打印棋盘——本质上就是打印数组 4.游戏过程——1.玩家走棋 2.…...

ehcache3多级缓存应用

项目中如果有使用大量的本地缓存场景&#xff0c;可以使用redisehcache组合缓存&#xff0c;优先使用ehcache本地缓存&#xff0c;本地缓存没有查询到再使用redis缓存 可看前文中如何集成 本地缓存使用存在的问题 1、本地缓存如何保证缓存的是最新值 可定义版本号、自增id或者…...

C# WinForm —— 24 Threading.Timer 组件介绍与使用

1. 简介 System.Threading.Timer 多线程 轻量级 精度高 提供以指定的时间间隔对线程池线程执行方法的机制 和System.Timers.Timer 类似&#xff0c;每隔一段时间触发事件&#xff0c;执行操作(不是由UI线程执行的)&#xff0c;即使事件中执行了比较耗时的操作&#xff0c;也…...

03-07Java自动化之JAVA基础之循环

JAVA基础之循环 一、for循环 1.1for循环的含义 for&#xff08;初始化语句;条件判断;条件控制或–&#xff09;{ ​ //代码语句 } 1、首先执行初始话语句&#xff0c;给变量一个起始的值 2、条件判断进行判断&#xff0c;为true&#xff0c;执行循环体中的代码语句 ​ …...

【人工智能Ⅱ】实验8:生成对抗网络

实验8&#xff1a;生成对抗网络 一&#xff1a;实验目的 1&#xff1a;理解生成对抗网络的基本原理。 2&#xff1a;学会构建改进的生成对抗网络&#xff0c;如DCGAN、WGAN、WGAN-GP等。 3&#xff1a;学习在更为真实的数据集上应用生成对抗网络的方法。 二&#xff1a;实验…...

vmware将物理机|虚拟机转化为vmware虚机

有时&#xff0c;我们需要从不同的云平台迁移虚拟机、上下云、或者需要将不再受支持的老旧的物理服务器转化为虚拟机&#xff0c;这时&#xff0c;我们可以用一款虚拟机转化工具&#xff1a;vmware vcenter converter standalone&#xff0c;我用的是6.6的版本&#xff0c;当然…...

redis 高可用及哨兵模式 @by_TWJ

目录 1. 高可用2. redis 哨兵模式3. 图文的方式让我们读懂这几个算法3.1. Raft算法 - 图文3.2. Paxos算法 - 图文3.3. 区别&#xff1a; 1. 高可用 在 Redis 中&#xff0c;实现 高可用 的技术主要包括 持久化、复制、哨兵 和 集群&#xff0c;下面简单说明它们的作用&#xf…...

封装tab栏,tab切换可刷新页面

dom结构 <template><div class"container"><!-- tab栏 --><div class"border-b"><tabs:tabsList"tabsList":selectTabsIndex"selectTabsIndex"tabsEven"tabsEven"></tabs></div>…...

JavaScript第八讲:日期,Math,自定义对象

目录 前言 日期 1. 创建日期对象 2. 年/月/日 3. 时:分:秒:毫秒 4. 一周的第几天 5. 经历的毫秒数 6. 修改日期和时间 Math 1. 自然对数和圆周率 2. 绝对值 3. 最小最大 4. 求幂 5. 四舍五入 6. 随机数 自定义对象 1. 通过 new Object 创建对象 2. 通过 funct…...

php质量工具系列之phploc

phploc是一个快速测量PHP项目大小的工具 结果支持raw csv xml json格式&#xff0c;可输出文件或者打印到控制台 安装 PHAR方式 wget https://phar.phpunit.de/phploc.pharphp phploc.phar -vComposer方式(推荐) composer global require --dev phploc/phplocphploc -v使用 …...

创建模拟器

修改模拟器默认路径 由于模拟器文件比较大&#xff0c;默认路径在C:\Users\用户名.android\avd&#xff0c;可修改默认路径 创建修改后的路径文件 D:\A-software\Android\AVD添加系统变量ANDROID_SDK_HOME&#xff1a;D:\A-software\Android\AVD重启Android Studio 创建模拟…...

【Java】接口详解

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量。 一个简单的接口代码示例 interface IShape { void draw(); } class Cycle implements IShape { Override public void draw() { System.out.println…...

去掉el-table表头右侧类名是gutter,width=17px的空白区域(包括表头样式及表格奇偶行样式和表格自动滚动)

代码如下&#xff1a; <el-table:data"tableData"ref"scroll_Table":header-cell-style"getRowClass":cell-style"styleBack"height"350px"style"width: 100%"><el-table-column prop"id" l…...

3079. 求出加密整数的和

给你一个整数数组 nums &#xff0c;数组中的元素都是 正 整数。定义一个加密函数 encrypt &#xff0c;encrypt(x) 将一个整数 x 中 每一个 数位都用 x 中的 最大 数位替换。比方说 encrypt(523) 555 且 encrypt(213) 333 。 请你返回数组中所有元素加密后的 和 。 示例 1&…...

奶茶店、女装店、餐饮店是高危创业方向,原因如下:

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 现在的俊男靓女们&#xff0c;心中都有一个执念&#xff1a; (1)想证明自己了&#xff0c;开个奶茶去…… (2)想多赚点钱了&#xff0c;加盟餐饮店去…… (3)工作不顺心了&#xff0c;搞个女装店去…… 但凡抱着…...

嵌入式笔试面试刷题(day16)

文章目录 前言一、PWM波形的占空比计算公式是什么&#xff1f;二、ADC和DAC在嵌入式系统中的应用场景有哪些&#xff1f;三、watchdog定时器的作用及其在系统中的使用是什么&#xff1f;四、JTAG接口在嵌入式开发中的作用是什么&#xff1f;五、实时操作系统(RTOS)的任务调度策…...

【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别

目录 一、 动态SQL1.1 \<if>标签1.2 \<trim>标签1.3 \<where>标签1.4 \<set>标签1.5 \<foreach>标签1.6 \<include>标签 二、 #{}与${}的区别2.1 #{}是预编译sql&#xff0c;${}是即时sql2.2 SQL注入2.3 #{}性能高于${}2.4 ${}用于排序功能…...

[Zer0pts2020]easy strcmp 分析与加法

查壳 Ubuntu上的64位程序 第一步应该尝试运行一下 啥也不是 (这里我改了程序,原来应该是a1>1) 但是我动调发现a1值是1 我就改了判断 但是还是没什么用 也找不到a2的引用 找一下有没有什么improt调用 发现还是啥也不是 思路这里断了 刚好这个程序几个代码而已 函数看…...

力扣7. 整数反转

给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff09;。 示例 1&#xff1a; 输…...

Mac/Linux getline 无法读取文件内容(读取内容无法显示)

如下面代码 #include <iostream> #include <fstream>using namespace std;int main() {string file_name "1.txt";std::ifstream file(file_name);if (file.is_open()) {std::string line;while (std::getline(file, line)) {char c line.back();cout…...

NBM 算法【python,算法,机器学习】

朴素贝叶斯法&#xff08;Naive Bayes model&#xff09;是基于贝叶斯定理与特征条件独立假设的分类方法。 贝叶斯定理 P ( A ∣ B ) P ( B ∣ A ) ∗ P ( A ) P ( B ) P(A|B)\frac{P(B|A) * P(A)}{P(B)} P(A∣B)P(B)P(B∣A)∗P(A)​ 其中A表示分类&#xff0c;B表示属性&…...

spark3.0.1版本查询Hbase数据库例子

需求背景 现有需求&#xff0c;需要采用spark查询hbase数据库的数据同步到中间分析库&#xff0c;记录spark集成hbase的简单例子代码 import org.apache.hadoop.hbase.HBaseConfiguration import org.apache.hadoop.hbase.client.{ConnectionFactory, Scan} import org.apach…...

android高效读图方式——Hardwarebuffer读图

安卓上有许许多多使用OpenGL来渲染的原因&#xff0c;比方说做特效/动画/硬解/人脸识别等等。渲染完成后如何从gpu中把数据快速读取出来也是高效图像处理中的重要的一环。 相对于glReadPixel的同步读取方式&#xff0c;安卓GLES3.0提供了更高效快速的Hardwarebuffer读图方式&a…...

悉数六大设计原则

悉数六大设计原则 目录 悉数六大设计原则前言☕谁发明了设计模式设计原则设计原则与设计模式的关系 单一职责什么是单一职责不遵循单一职责原则的设计遵循单一职责原则的设计单一职责的优点示例代码&#xff1a; 里氏替换原则什么是里氏替换原则示例代码&#xff1a;违反里氏替…...

hdfs复习

一.hadoop概述 1.4高&#xff08;优势&#xff09; 1&#xff09;.高可靠性&#xff1a;hadoop底层多个数据副本&#xff0c;即使某个计算节点存储出现故障&#xff0c;不会导致数据丢失。 2&#xff09;.高扩展性&#xff1a;可以动态增加服务器节点。 3&#xff09;.高效…...

css-Ant-Menu 导航菜单更改为左侧列表行选中

1.Ant-Menu导航菜单 导航菜单是一个网站的灵魂&#xff0c;用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航&#xff0c;顶部导航提供全局性的类目和功能&#xff0c;侧边导航提供多级结构来收纳和排列网站架构。 2.具体代码 html <!-- 左侧切换 --><…...