今天我们来深入了解一下各项数据在内存中的存储
一 . 整数在内存中的存储
这个众所的周知昂,咱们之前在讲解操作符的时候提到过一嘴,整数在内存中的存储形式——那就是以二进制的形式储存,记不清也没关系,很简单,咱们今天一起来回顾一下:
整数的二进制表现形式有三种:原码、反码、补码。有符号的整数,三种表现形式均分为符号位和数值位两部分,在我们的最高位的第一位就是我们的符号位,(二进制的最左边),其余剩下的就是数值位。符号位都用 0 来表示 正 ,用 1 来表示 负 。而正负数的原、反、补是略有差异的:
(1)正负数原、反、补的差异
1 . 1 . 原、反、补换算原则:
原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码
反码:将原码最高位的符号位不变,其余数值位的位置依次按位取反即可得到反码
补码:在反码的基础上 + 1 得到补码
注意:在我们的计算机中整型存储的二进制就是补码的形式,这是为什么呢?如下:
在我们的计算机中,数值一律用补码来表示和存储,原因在于:使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器),此外,补码与原码的互相转换,其运算过程是相同的,不需要额外的硬件电路
1 . 2 . 正负数原、反、补的差异:
正数:原码、反码、补码完全相同(即:算出原码,原码 = 反码 = 补码)
负数:原码、反码、补码各不相同,遵循他们之间的换算原则
1 . 3 . 举例
二 . 浮点数在内存中的储存
了解完整数的储存,咱们再来看看浮点数的储存
常见的浮点数为:2.00271这样的,或者1E10(1乘10的10次方)、1E-10(1乘10的-10次方)这样的,浮点数类型包括:float、double、long double等,浮点数范围:float . h 中定义
咱们可以先来看一道例题昂:
大家可以看一下昂,这个答案我想可能与绝大多数人所想的有一定的出入吧?这是因为诸君还没有了解到浮点数在内存中的储存原理,我们暂且将它放在一旁,接下来我们通过对浮点数的储存的学习过后,再来看它就很小儿科了
(1)浮点数的储存
在我们上面的代码中,num 和 Float 在内存当中明明是同一个数,为什么浮点数和整数的解读会出现如此之大的差异呢?诸君莫急,我们要理解这个结果,就一定要搞懂浮点数在计算机内部的表达方式:
根据我们国际标准 IEEE (电气和电子工程协会)754:任意一个二进制的浮点数 V ,可以将其表示成以下形式:
文字始终是干瘪的,我来举个例子帮助诸君理解记忆:
十进制的 5.0 ,咱们转换成二进制就是:101.0,也就是:1.01*2^2
那么,按照上面给出的格式,我们相对应的:S = 0,M = 1.01,E = 2
IEEE 754 规定:
对于32位浮点数,最高的1位村储存符号位S,接着8位储存指数E,剩下的23位储存有效数字M
对于64位浮点数,最高的1位村储存符号位S,接着11位储存指数E,剩下的52位储存有效数字M
形式如下图:
(2)浮点数存储的过程
我们的 IEEE 754 对于有效数字 M 和指数 E 还有着一些特别的规定:
( 2 . 1 )有效数字 M :
前面提到,我们的有效数字 M 的范围是:1 < M < 2 。那么也就是说,咱们的 M 永远都是 1 点几,大家想一想是不是这个道理,所以为了精益求精,咱们的 IEEE 754 规定:在计算机内部保存有效数字 M 时,会默认这个数的第一位总是 1 ,因此可以被舍去,咱们只需要保存小数点后面的部分即可。就列如:1.01,咱们只需要保存 01 即可,等到我们读取的时候,计算机自动会将第一位的 1 加上去
这样做的目的:可以节省一位有效数字,以 32 位浮点数为例,留给 M 只有 23 位,将第一位的 1 舍去后,咱们就可以保存 24 位有效数字
( 2 . 1 )指数 E :
1 . 指数 E 的储存
我们指数 E 的情况就相对复杂
首先,E 为一个无符号整数(unsigned int),而这就意味着,如果 E 为 8 位,它的取值范围为:0~255;如果 E 为 11 位,它的取值范围为:0~2047。但是,我们要知道,科学计数法中的 E 是可以出现负数的,所以 IEEE 754 规定,在我们存入内存时,E 的真实值必须再加上一个中间数,这个中间数是多少呢?对于 8 位的 E ,中间数为 127 ;对于 11 位的 E ,中间数为 1023
例如:2^10 的 E 为10,所以保存成 32 位浮点数时,必须表现为:10 + 127 = 137,即10001001
2 . 指数 E 的取出
指数 E 的取出分三种情况:
(1)正常情况:E 不全为 0 或者不全为 1
此时,我们浮点数就采用规则中所表示的,即指数 E 的储存计算值减去127(1023),得到真实值,再将有效数字 M 前加上第一位的 1
例如:0.5 的二进制形式是 0.1,这个时候有同学就要问了,为什么不是 0.101 呢?这个0.1 咋来的呢?我们小数点后的二进制转换跟小数点前可以不一样昂,诸君切莫一概而论。我们的 0.5 也就是1/2 嘛,1/2 = 1*2^(-1),所以得出结果:0.5 的二进制就是 0.1
那我们由于规定正数的部分必须为 1,即小数点向前移一位,所以为:1.0*2^(-1),所以其阶码为 -1 + 127 = 126,则二进制表示为 01111110,而尾数 1.0 去掉整数部分的 1 为 0,再补齐剩下的22位,综上所述,0.5 的二进制表现形式为:
(2)E 全为 1
当我们的 E 全为 0 时,浮点数的指数 E 等于 1 - 127(1 - 1023)即为真实值,此时有效数字 M 不在加上第一位的 1,而是直接表示为 0.000000 这样,就表示为 ± 0 —— 无线接近于 0 的数,例:
(3)E 全为 1
当指数 E 为全 1 ,表示正负无穷大,例:
讲到这里,关于浮点数在内存中的存储我们就已经了解的差不多了
接下来咱们已经学成归来是吧,那就去会一会刚刚那道例题!
例题解析:
大家可以看到昂,我在对应行的代码上都做了详细的注释解析,我相信诸君都是聪明人,不用我多说了,肯定都懂的。如果有疑问的欢迎在评论或者私信交流哈!
三 . 大小端字节序
(1)大小端字节序的概念
什么叫大小端字节序呢?这个名词大家可能是第一次听说,但其实它也是跟我们的内存有一定关系的:超过一个字节的数据在内存中储存的时候,就会有存储顺序的问题,按照不同的储存顺序,我们分为大端字节存储和小段字节序存储
大端字节序存储:数据的低位字节内容保存在内存的高地址处;反之,数据的高位字节内容保存在内存的低地址处
小端字节序存储:数据的低位字节内容保存在内存的低地址处;反之,数据的高位字节内容保存在内存的高地址处
(2)为什么会有大小端之分
这是因为在计算机系统中,我们都是以字节为单位,每个地址单元都对应着一个字节,一个字节为 8 个 bit 位,但是在 C 语言系统中除了 8 bit 的 char 之外,还有 16 bit 的 short 型,32 bit 的 long 型(要看具体的编译器)。另外,对于位数大于 8 位的处理器,列如 16 位或者 32 位的处理器,由于寄存器宽度大于一个字节,那么必然会存在着一个如何将多个字节安排的问题,因此就导致了大端存储和小端存储
例如:我们有一个三位整数:123,个位数的 3 就是我们的低位字节,百位数的 1 就是我们的高位字节,以此类推……
我们数字位的低位到高位是从右向左,地址位的低位到高位是从左向右
如图,咱们用这个例子通过调试观察内存就能很清晰地看到我们的存储是倒着放的:数据的低位字节内容保存在内存的低地址处;反之,数据的高位字节内容保存在内存的高地址处,这就是我们的小端字节序存储
(3)验证我们的系统是大端还是小端
我们了解了大小端字节序存储的判断逻辑后,就可以通过自己来写一个代码验证一下我们的电脑系统是大端字节序存储还是小端字节序存储:
如图,这段代码原理很简单昂,我们先创建一个整数 a,给它赋值为 1,我们 1 在内存中的十六进制存储应该表现为 01 00 00 00 ,我们再 & a,将 a 的地址赋给指针 p,对 p 解引用,若其第一个字节为 0 ,则表示该系统是将我们的低位字节 01 放在了高地址处,为大端字节序存储,若不是 0,则为小端字节序存储
当然,我们还可以通过设计一个函数来实现它:
OKK,有关于各类数据在内存中的存储我们就讲到这个地方啦,这一部分的知识有一点点难理解,诸君勤当勉励之。如果此篇的知识点对大家有所帮助的话,就顺手点个关注点个赞支持一下吧。就这样啦,咱们下期再见。与诸君共勉!!!
标签:存储,字节,浮点数,储存,内存,数据,我们 From: https://blog.csdn.net/Dove_Xxx/article/details/143099976