1.整型在内存中的存储
我们要先知道整型在内存中是以二进制的形式存储的,所以这里我们要先介绍三种二进制的形式
1.原码,补码,反码
整数的原,反补码都是相同的,而负数的则不同,而且整型在内存中,二进制是以补码的形式存入的。
反码:符号位不变,其他位,按位取反,1变0,0变1.(这里在32bit下计算的,最前面一位为符号位)
补码:反码+1就是补码
我们这里以15,-15为例。
15的原反补都是
0000 0000 0000 0000 0000 0000 0000 1111
-15
原码:1000 0000 0000 0000 0000 0000 0000 1111
反码:1111 1111 1111 1111 1111 1111 1111 0000
补码:1111 1111 1111 1111 1111 1111 1111 0001
2.大小端
这里以15为例
15在16进制下的形式为
0x0000000f
但是VS2022下表示形式确实反过来的,那么这就是我们要说的大小端的问题
这里我们把低位字节序放在低地址,高位字节序放在高地址,这就叫做小端存贮,也就是上面VS2022的存储方式,而大端存储则与其相反。那么这里你可能有疑问,为什么要这样做呢?
这里是为了处理如何将多字节安排的问题。
2.浮点数在内存中的存储
在讲浮点数的存储之前我们先复习一下C语言中如何表示科学计数法,例如1E10,就表示1*10^10;
*例题
int a = 10;
float* p = &a;
printf("%d\n", a);//?
printf("%f\n", *p);//?
*p = 10.0;
printf("%d\n", a);//?
printf("%f\n", *p);//?
这里大家可以先自己算一算这里的四个值是多呢?
这里给出了这四个值,在这里我们可以得出结论,浮点数的存储和整形的存储是不同的,定义整形的变量只能用整形的方式提出,浮点数亦是如此。接下来我们便要围绕这个例题进行介绍。
1.浮点数在内存中的存储公式
在规定上浮点数的存储公式为(-1)^S*M*2^E.以数字5.5为例。我们先写出它的二进制101.1,接着我们把它转化为科学计数的形式,1.011*2^2。我们把上面的公式可以看成三个式子
[(-1)^S]*(M)*(2^E) 第一部分表示符号,5.5为正S=0,M就是1.011,E就是2;众所周知在32位计算机上float是4字节的,那么这个式子上面是如何存储的呢?
这个就是SEM在float和double两种类型下的分布。再存入的时候S就占1bit没什么特殊的,注意在存储M的时候我们只存入小数点后面的数字,这样我们就可以让小数位多一位,取的时候再在前面补上1就可以了。在存E的时候较为复杂,我们都知道在输入的时候浮点数也可以去到负数但是在上述的存储中不论是float还是doubleE所占的bit没有符号位所以我们在存储的时候规定了一个中间值float的中间值是127和1023.然后就是如何取出了同样S没有特殊,M我们已经提到了,最后就是重点的E分为三种情况
第一种非全0或非全1-------这种我们就正常存入的时候加了127,取的时候就减掉
第二种全0---------------------这种情况我们就要先考虑是怎么出现的全0,我们加上了127还出现了全0,说明原本数字非常之小,所以啊,我们取的时候M就不加0了,表示一个无线接近0的数。
第三种全1---------------------这种情况和全0一样的考虑方法,最后就是表示一个正负无穷大的数字。
3.总结
了解完浮点数的存储我们就可以对刚刚的例题做出解释
我们重点看2和3,对于二,E为全0所以根据我们上面说的,最后就变成了0,再看三二进制我们可以拿给计算器去算
我们可以看到二进制转化为10进制和上面编译器给出的答案一模一样所以我们的猜想是正确的。
反思
这个章节其实对我们写代码的作用不大因为这种东西太底层了,但是这个可以帮助我们去理解代码到底是怎么变成这个样子的,为什么可以得出这样的结果,这个在无形中提升了我们对于代码的理解