C语言·数据在内存中的存储

1. 整数在内存中的存储

        在之前的操作符讲解的章节中我们就提到过:

        有符号整数的二进制表示方式有三种,源码、反码、补码,无符号整数没有这样的区分方式,可以理解成直接就用源码储存,正整数的原反补是相同的,负整数有源码符号位不变,其他按位取反得到反码,反码加一得到补码的规律,对于整形来说数据在内存中是以补码的形式储存的。那为什么要发明反码这个东西呢?因为使用补码计算可以将符号位和数值位统一处理,不需要额外的硬件电路来进行不同符号数据的运算

        

2. 大小端字节序和字节序判断

        我们观察一个现象

        通过观察变量a的内容在内存中的存储,我们发现它看起来是倒着存的,存的是 78 56 34 12 这个就是进行了小端字节序存储

        

2.1 什么是大小端

        超过一个字节的数据要存放在内存中的时候,就会有储存顺序的问题出现,当我们要用到这个储存的数据的时候可以通过储存顺序把它还原出来。按照不同的储存顺序我们将储存方式分为大端字节序存储和小段字节序存储,这里强调“字节序”三个字因为这个顺序是以字节为单位观察的,一个字节内部不会再有什么什么奇怪的存储顺序了,有符号整形都是存补码,这也是为什么12没有被倒过来

        大端存储模式:是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。

        小端存储模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。

              

        我们一般接触的都是小端存储模式,而如KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

2.2 练习

2.2.1 写一个代码,来判断当前机器是大端还是小端

2.2.2 有符号和无符号数的存储和输出

2.2.3 char类型数据的取值范围

        signed char 首个比特位是符号位,有7个数值位,所以表示的数据范围是-128~127

        unsigned char 没有符号位,有8个数值位,所以表示的数据范围是0~255

2.2.4 char类型数据的轮回

        第一题是关于有符号char类型数据的轮回

        第二题是关于无符号char类型变量数据的轮回

2.2.5 指针与大小端存储的结合

          

        赋值给ptr1的这种语句在指针篇我们已经见过很多次了,它指向了整个数组的下一个字节

        ptr[-1] 等价于 *(ptr1 - 1) 因为ptr1是int型指针变量,所以这句话的意思是向左移动4个字节解引用,最终找到 4

        接下来我们分析ptr2

        (int)a + 1 将指向数组首元素的指针强制转化成 int 类型 +1,相当于将指向数组首元素的指针直接在数值上+1,当然,这个数值上的直接增加必须发生在32位操作系统环境下,否则,在64位环境下,指针变量的大小是8个字节,强制转换成int型会发生截断,截断后就不是原来的地址数值+1了

        (int*)((int)a + 1) 地址数值+1后再将数值转换回 int* 类型,这样做结果就是跳过了1个字节

        因为我的系统是小端存储的,所以稍加分析,*ptr2 得到 2000000

        我把这道题的数据在内存中的存储,形象一点的画出来就是这个样子

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

        常见的浮点数:3.14159 、 1E10 (1乘以10的10次方)

        浮点数的取值范围定义在 float.h 中

3.1 浮点数的存储

        根据国际标准IEEE 754(电气和电子工程协会),任意一个二进制浮点数V可以表示成下面的形式:

         V = (-1)^S * M * 2^E

        (-1)^S  表示符号位,当S=0时,V为正数;当S=1时,V为负数
         M        表示有效数字,M是大于等于1,小于2的
         2^E     表示指数位,是无符号的类型

接下来我举例说明如何将一个十进制小数转换成V的形式表示:

        当我们得到了S、M、E的值了,只需要解析这三个数值就可以得到一个小数,所以现在我们该思考应该以什么形式把这三个数值存进内存即可

       在32位环境下,最高的一位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

      在64位环境下,最高的一位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

                    ​​​​​​​      

        这些只是笼统的概括一下浮点数在内存中大概是怎么存的,下面我将详细说一些细节

3.1.2 浮点数取的过程

        上面说过M是一个大于 1 小于 2 的数,所以说,在每次转成V的表达形式后的时候一定会成为一个1点多的数,既然每次的第一个比特位存的都是1,那么它就可以舍去,直接存小数部分,这样还可以节省一个有效数字位

        比如在存 1.011 的时候只保存 011 等到读取这个数的时候再把1加上,以32位环境为例,M给了23个位,将头一个1舍去,等于可以保存24个有效数字了

        当存储E的时候IEE 754中规定,在32位环境下,存E的时候要给它加上一个127,在64位环境下,存E的时候要加上一个1023。这种加上一个数的操作我们叫做 修正

        比如说,在32位环境下要存刚才那个 E=2 ,那么存到内存的数值应该是 2 + 127 = 129 ,即 1000 0001

        

3.1.2 浮点数取的过程

        在取 S 和 M 的时候直接取就可以,但是在取指数 E 的时候分为三种情况

        E 不全为0 或 不全为1:这时,将E的值减去127(或1023),得到E的真实值,再将有效数字前面加上第一位的1

        E全为0:这时,指数E为 1-127=-126 (或者1-1023=-1022),有效数字M不再加前面的1,而是还原成0.xxxx的小数,这样做是为了表示0或无限接近于0的数

        E全为1:这时,表示正负无穷大的数字

        

3.2 浮点数的比较

        前面说过M是按照二进制的比重写出来的,也就是说有些浮点数在内存中无法精确的保存,它们总是无限趋近于那个值,但是却无法精确到它

        ​​​​​​​        ​​​​​​​        

        所以说在比较两个浮点数的时候如果直接 == 可能会出问题,所以我们一般按照精度比较,两个数的差值不超过某个精度我们就认为他俩相等

        这段代码中我将精度设置为0.0001,当两数差值不超过0.0001我就认为它们相等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值