1.整数在内存中的储存
整数在内存中是以二进制的形式进行储存,每个整数都有对应的二进制表示,并且都有:原码,补码,反码三个概念。对于正整数来说,这“三码”是一模一样的,而对负整数来说就有不同的表示。
在了解这“三码”之前我们需要知道,整型是四个字节的大小,有4*8=32个比特位,最高位是符号位,例如:1000 0000 0000 0000 0101,这串二进制数字的红色1,就是这串二进制的符号位,表示这个数是负数,而其他都是数值位。反之,如果最高位是0,则说明这个数是没有符号的整数。那为什么无符号整数的“三码”相同呢?接下来就来介绍一下这三个码。
1.1 什么是原码、补码、反码
原码:原码就是我们所看到的二进制,比如说5的二进制表示是0101,当然,前面还有很多很多0,我们这里就不写了。这便是正数的二进制表示。,如果是-5呢,那只需要在最高位的0变成1就可以了(是第32位的0哦~)。
补码:补码就是由原码变来的,将原码进行取反,得到的就是补码。还是5——0101,取反之后就是1010.取反的时候要注意,符号位是不能改变的。
反码:反码就是反码+1,也就是原码取反后+1.在计算机里,整型就是以其反码的形式储存的。反码要得到原码也只要进行取反后+1即可。
1.2 为什么计算机里用反码储存数据
为什么是用反码的形式储存呢?
因为用反码储存可以更方便数据的直接运算;CPU里只有加法器,说明计算机只能进行加法运算。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
2.大小端字节储存顺序
我们来看一个代码的调试:
这里我们可以看到整型a是倒着储存的。
2.1 什么是大小端
首先我们要知道,什么是大小端储存?
大端储存模式:将数据的低位储存到高地址处,数据的高位储存在低地址处。
小端储存模式:将数据的高位储存在高地址处,数据的低位储存在低地址处。
在数据超过一个字节的时候就会有大小端储存。那为什么会有大小端储存呢?
2.2 为什么会有大小端
因为数据在内存中都是以二进制的形式储存,一个字节就有8个比特位,但是我们知道不仅有char类型的数据,还有short、int、long等类型,它们的大小都超过了1个字节,有非常多的比特位。这时候就需要约定好,这些比特位应该是按照大端还是小端储存,这样数据才不会杂乱无章。一会是小端储存,一会是大端储存,这样显然不行。
3.浮点数在内存中的储存
我们常见的浮点数有:3.14159,1E10等,浮点数类型的成员有:float、double、long double。浮点数范围的定义在头文件:float.h里
3.1 引例
#include <stdio.h>
int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
这段代码的结果:
明明n在内存中储存的就是9,那为什么从不同的浮点类型的角度,输出的结果就是不一样呢。接下来我们就要来了解浮点数在内存中是怎么样的储存形式。
3.2 浮点数在内存的储存
根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V:是浮点数的值
S:决定了浮点数的正负,如果为0,则为正,为1就为负
M:表示有效位,但是M是大于等于1,小于2的
E:这是2的E次幂
例:5.0的二进制表示是101.0,写成上面的形式就是1.01*2^2.
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
可能看着有点懵,将这个表示方法类比科学计数法,科学计数法是表示十进制的数,例子里面是二进制数,2的E次幂就相当于科学计数法10的E次幂。
IEEE 754规定:
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
3.2.1 浮点数存储的过程
我们上面说了M的取值是[1,2)的,那么一个浮点数1.xxxxxx里的个位1就可以省略,这样储存的时候就可以多一位去储存小数部分,32位的浮点数的M就有24位,64位就有53位。
E的储存:E是一个无符号整型,我们知道在科学计数法里面,10的幂是可以为负的,这里2的幂也是可以为负的,但是我们又不能在表示负数,所以我们对于指数E的储存都要加上一个中间值,8个比特位的值是0~255,它的中间值就是127,比如2^10的E是10,在计算机里面的储存就是10+127=137,写成二进制就是10001001.
3.2.2 浮点数取出的过程
取出时,E有三种情况:
E不全为1或者0:这时只需要将储存好的E减去127或者1023(64位的中间数)还原即可。
E全为0:这时候就是用来表示非常小的小数。这时E的值就是它的真实值,而M也不用加上1,而是直接还原为0.xxxxxxx的小数。
E全为1:这时表示正负无穷大。
3.2.3 回到引例
看到输出全为0:9的二进制是1001,当从浮点数的角度去输出时,先把这段序列变成浮点数的储存形式,0000 0000 0000 0000 0000 0000 0000 1001,从浮点数的角度去解读时,E全为0,就说明这是一个无限趋近于0的数字,表示为:
V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146),V是一个非常非常小的数字,用十进制的浮点数表示时就为0.0000000.
再看到输出一串很大的数字:n先是被改成了9.0,变成了一个浮点型,那么V=(-1)^0*1.001*2^3
S=0,E=3,在内存里就是E=3+127=130,M=001,个位的1被拿掉了,后面的位都补0.
所以换成二进制就是0 10000010 001 0000 0000 0000 0000 0000。这个就是9.0在内存的储存二进制序列,也就是反码(上面提到的),然后再从整数的角度去输出(输出原码),答案就是原码的十进制形式1091567616。
希望该文章对你有所帮助,感谢观看!