整数和浮点数在内存中的存储

1. 整数在内存中的存储形式

        整数在内存中是以二进制补码的形式来存储的,那什么是补码呢???这里就要涉及到一些知识点了。

        二进制的表示形式有三种 : 原码  , 反码  , 补码

        整数的原反补码相同,所以以下内容为负整数补码的计算方法。

1.1 原码

        原码就是数字的直接表现形式(二进制位表示)

1.2 反码

        原码符号位不变(第一个位为符号位),其他位取反,得到的就是反码

 

1.3补码

        反码+1,得到的就是补码,整数在内存中存放的就是补码

        在内存中是以二进制补码存放的,但在监视窗口,是16进制显示的,主要是因为二进制太长,不好展示。

        在图片中我们可以看到,为什么10的十六进制在内存中是反着放的,这是有什么说法吗?这里就要涉及到所谓的大小端字节序了。

2.大小端字节序

        这里上一段代码:

       我们看到,我明明存进去的是11223344,为什么在内存中是倒过来存放的呢?这就是大小端字节序的原因

        那什么是大端?什么是小端呢?

 2.1什么是大小端字节序

        超过一个字节的数据在内存中存储是,就有存储顺序的问题,为了让我们存进去的值,在取出来时更方便,所以就有了大小端。

2.2 大端字节序存储

               以字节为单位,把一个数据的高位(最大值)存放在低地址处,把低位(最小值)存放在高地址处

2.3 小端字节序存储

        以大端相反

        以字节为单位,把一个数据的低位(最小值)存放在低地址处,把高位(最大值)存放在高地址处

2.4 为什么要有大小端

        为什么会有大小端模式之分呢?

        这是因为在计算机系统中,我们是以字节为单位存储的,每个内存单元都对应着一个字节,一个字节为八个比特位,但在C语言中,除了8bit位的char以外,还有16bit位的short和32比特的ilong(具体看编译器),对于大于8位的处理器,如16位和32位处理器,由于寄存器宽度大于一个字节,所以就会出现字节顺序存放的问题,因此导致了大端存储模式和小端存储模式的存在。

2.5练习

       设计一个小程序来判断当前机器的字节序

        这串代码怎么去理解呢?让我们一步步来

        首先,创建一个变量为i,初始化为1,1的二进制为00000001(只查看四个字节),此时1在内存中如果是大端存放,就是00 00 00 01 ,如果是小端存放就是01 00 00 00

                如果这时编译器如果是大端,取出来的就是低位的第一个字节 00(这里我依旧只用四个字节来展示)

        如果编译器为小端,取出的就是高位的第一个字节 01

        然后对它解引用,如果是大端,解引用后得到的就是0 ,如果是小端,解引用后得到的就是 1,把解引用后得到的值存进一个变量里。

        紧接着我们对ret里面的值进行判断就可以知道是大端模式还是小端模式了

2.6 练习题

        上面我们了解了整数在内存中如何存储,那接下来我们来做道练习题

        这段代码的输出结果是什么?这里有人会说,这个简单,三个-1嘛,有什么难的,但结果真的是三个-1吗?让我们运行看看

        这里我们看到,a和b确实是-1,但c为什么是255呢?让我们一步步来解析一下,前面我们学到整数在内存中存放的是二进制补码,那-1的补码是什么

        由于char类型是一个字节,所以这串补码在存进去时,会进行截断

        打印时,我们使用%d进行打印,%d打印的是整数,所以对char进行整形提升,负数高位补符号位

        我们在内存中存进去的是补码,但是取出来时要改成原码

原码改补码 = 取反,+1

补码改原码 = -1,取反

        -1的补码为全1,打印结果为1,所以a和b的打印结果都是-1

        那c的打印结果为什么是255呢?首先我们得知道unsigned char是无符号的,在存进内存时跟a和b的补码都一样,问题就出现在取出来的时候,char类型在存进去时进行了截断,取出来时就要整形提升,由于a和b为有符号数,取出来时高位补的是符号的,但c为无符号数,高位补的是0

        前面也说过正整数的原反补相等,所以取出来的原码就是上面图片中的,这个原码换算成整数就是255,所以c的打印结果为255.

        那么对整数在内存中如何存储已经初步讲解完毕,接下来,讲解浮点数(float ,double)类型在内存中是如何存储的。

3.浮点数在内存中的存储

        浮点数家族 : float ,double ,long double

3.1浮点数的存储

        整数和浮点数在内存中的存储方式是有区别的,根据国际IEEE(电气和电子工程协会)754规定,任何一个二进制(V)可以表现成以下形式:

        举例来说:十进制5.5转换成二进制就是 101.1,为什么是101.1呢?这是因为小数在计算是的权重不一样

        5.5 = 101.1 ,换算成科学计数法 101.1 = 1.011 * 2^2

IEEE 754 规定:

对于32位的浮点数,最高的一位存储符号位,接着的8位存储指数E,剩下的23位存储有效数字M

对于64位的浮点数,最高的一位存储符号位,接着的11位存储指数E,剩下的52位存储有效数字M

                                ·                        float 类型浮点数内存分配

                                                         double类型浮点数内存分配

3.2 浮点数的存储过程

        IEEE 754 对有效数字M和指数E,还有一些特殊规定;

       前面提到过 1 <= M < 2 ,M可以写成1,xxxxxx形式,其中xxxxxx代表小数。

M有效数:

        IEEE754 规定,在计算机内部保存M时 ,默认第一位为1,所以可以舍去,只保存后面的小数部分,比如保存1.01的时候,舍去前面的1,只存后边的01,等到读取的时候,再把1加上去,这样做可以节省1位有效数字,那32位浮点数为例,M可以存23位有效数,如果去掉1,就相当于存了24为有效数。

E指数:

        E就有一点复杂了,E是unsigned int(无符号整形)类型的,如果E是8位,取值范围就是0~255,如果E是11位,取值范围为0~2047,但是我们知道,科学技术法是有负数的(例:2^-1),

所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,它的中间数为127,对于11位的E,它的中间数为1023。

        比如: 2 ^10 ,E为10,在存入内存是要给指数E加上个中间值,10 + 127 = 137 ,转换成二进制就是10001001,所以在内存中E的指数位存的就是这串二进制。

3.3 浮点数从内存中提取的过程

        E从内存中取出的过程还分三种情况:

1. E不为全0或不为全1

        当E不为全0或不为全1时,浮点数的提取采用下面的规则表示:即指数E减去中间数,取得真实值,再将有效数字M前面加上1。

比如: 0.5 转换成二进制位 0.1,前面规定有效数字M的第一位必须是1,所以将小数点右移,

                                ​​​​​​​        ​​​​​​​        ​​​​​​​        0.1 = 1.0 * 2^(-1) ,

E 为 -1 ,加上中间值 -1 + 127 = 126 ,126的二进制位01111110

M为 1.0,舍去整数1 为 0 ,补齐0到23位

S 为 0 ,因为是正数

        所以完整的二进制就是

2.E为全0 的情况

        E为0的情况下,M的值可能是一个很小的数字,浮点数的E为 1-127(1-1023)即为真实值,有效数字M不在加上第一位的1,而是还原为0.xxxxx的小数,这样做是为了表示正负0,以及接近于0的很小的数字

3.E为全1的情况

        E为全1的情况下,M的值可能是很大的值,如果有效数字M全为0,表示正负无穷大(正负取决于符号位)

        整数和浮点数在内存中存储的基本知识就这些(不代表全部),那这篇文章就到此结束了,我们下一篇见。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值