目录
一背景:
二具体举例
三整数存储规则
四浮点数储存规则:
数据各部分存储如下:
一背景:
在我学到指针的时候,我知道指针类型默认就是它指向的类型,指针类型决定步长,步长换句话来说就是一次能访问的字节数,但是我突然发现,float*和int*的步长是一样的,那如果我把整型指针强制类型换为float*,然后去访问整型数据,又或者把浮点数指针强转为int*指针访问整数结果又会怎么样呢?
二具体举例
(1)如下代码
int n = 9;
float* p = (float*)&n;
printf("整型视角看待整数 : %d\n", n);
printf("浮点数型视角看待整数 :%f\n", *p);
*p = 9.0;
printf("整型视角看待浮点数 :%d\n", n);
printf("浮点数视角看待浮点数:%f\n", *p);
在这个代码中我们可以发现,我们在一段内存中按整型存储存入了9,如果用浮点数视角看待这段内存(浮点数指针访问整型),我们用%f打印结果为零,而用整数视角看待用float类型存储的数,打印出来的值更是非常奇怪,这说明浮点数和整数看待同一段内存是不一样的,为了弄清楚这个问题,我们就要好好了解浮点数和整数在内存的存储规则。
(2)相似代码
还有就是这个代码,千万要和举例1的代码区分好,我这里应该算是printf用%d打印%f,用%f打印%d的结果分析,一般一般不同类型的数据在赋值的时候 如果类型不一致 编译器会尝试进行隐式类型转换的,但是printf这里不会 如果类型不一致 无法解析了就按照解析失败处理 最后统一打印0了 。举例1是用浮点数的角度解析整数9在内存的存储,以及反着来解析浮点数, 我还是好好讲解一般浮点数存储和整数存储的不同吧。
三整数存储规则
整数的存储很简单,存储在内存的为数据的补码,数据分负数和正数,负数和正数在转为补码的时候略有不同。一般原反补关系如下:
原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码。
反码
将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码
反码+1就得到补码。
(1)正数的补码:正数的原,反,补码都相等
(2)负数的补码:负数的则需要上述原反补关系转换
四浮点数储存规则:
是时候搬出规定了,根据国际标准,任何一个浮点数x(包括float类型和double类型)都可以写成下面的形式,
(-1)^s*m*2^E
(-1)^s表示符号位,当s锁存数为0时,x为正数;当s所存数为1时,x为负数。
M表示有效数字,大于等于1,小于等于2;
2^E表示指数位;
对于32位的浮点数来说,最高位为符号位s,接着的为八位指数E,剩下的23位为有效数字M
双精度浮点数的储存和单精度浮点数是大同小异的
数据各部分存储如下:
1.M的存储:
前面说过,1≤M<2,也就是说,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。
IEEE754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
2.E的存储
c语言规定E为无符号整型(至于为什么是无符号整型,我个人觉得如果E也有符号位,s也是符号位,对于计算机来说要处理两位符号位,这个时候对于计算机来说直接把负数转为正数要简单的多),所以当E为八位时,取值范围为0到255,当E为十一位时,取值范围为0到2047,可是就我们刚刚举例的5.5来看,E的值为-1,这个时候c语言的处理就是把E的值都加127再存放到内存中去,但是如果是-128+127,结果为-1(至于为什么是加127,而不是128呢?我觉得理解为选127使得数据正负范围分布更大就可以了,+128时范围为5.877*10^(-39)到1.7*10^38,+127时范围为1.175*10^(-38)到3.4*10^(38),人为规定的每个人都有觉得对的理由)
既然存储计算机做了许多处理,在取出数据的时候同样需要许多处理将其还原为真实的数据。
3.E的取出
这个就比较复杂了,但这也正是上代码运行结果的重要理论基础。
(1)当E不全为0或者不全为1时
此时把E转换为十进制然后减去127即可
(2)当E全为0时
这说明E本来是-127,这已经很小的数了,所以当我们取出M的时候就不补1了,而是补零。
(3)当E全为1时
这说明E是255,2的255次方,这是一个非常大的数,当M全为零时可以看做原来的数字是趋近正无穷或者负无穷,具体要看s的值。
4.代码解释:
当我们在内存中存入整形数据9时,转换为二进制为00000000 00000000 00000000 00001001,从浮点数的角度来看,S为0,E全为零,M为0000000 00000000 00001001,这个时候的E已经能说明这是个很小的数了,计算机将其视为0,故此时打印结果为0
当我们存入浮点数数据9.0时,首先9.0表示为1001=(-1)^0*1.001*2^3,所以此时E为3,加127存到转为二进制1000 0010存到内存中,S为0,M为1.001,数据存到内存中为,0 10000010(E) 00100000000000000000000(M),而对于整数来说,这个三十二位的二进制就是2^30+2^24+2^20=1073741824+16777216+1048576=1091567616.
完结感言:当我们学了上面知识后,运用到实际上就可以大致知道储存一个数字是有极限的,也就可以更理智地看待拼夕夕的活动,只差零点1这都是套路(哈哈哈),接下来路还长着呢。终于又完成了一篇,很多时候我并不想钻研,因为那种越来越多问题出现不知道怎么解释的时候真的很折磨,好在都过来了,祝大家都能在探索的路上坚持下来。