C语言-整数和浮点数在内存中的存储-详解-下

博客主页:【夜泉_ly
本文专栏:【C语言
欢迎点赞👍收藏⭐关注❤️

C语言-整数和浮点数在内存中的存储-详解-下

1.前言

C语言-整数和浮点数在内存中的存储-详解-上中,我通过一个简单的例子展示了整数和浮点数在内存中的存储差异,并详细介绍了整数在内存中的存储。
本文将继续探讨浮点数在内存中的具体存储方式,并解释相关代码的运行结果。
示例代码回顾

#include <stdio.h>
int main()
{
	int n = 5.5;
	float* p = (float*)&n;
	printf("%d\n", n);
	printf("%f\n", *p);
	*p = 5.5;
	printf("%d\n", n);
	printf("%f\n", *p);
	return 0;
}

这段代码的运行结果如下:

5
0.000000
1085276160
5.500000

在上一篇文章中,我已经解释了这是由于整数和浮点数在内存中的存储方式不同所导致的。
本篇,我将详细介绍浮点数在内存中的存储,并解释上面代码的结果是如何得到的。

2.浮点数

2.1IEEE 754 标准

谈到浮点数的存储,永远离不开 IEEE 754

IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

根据其规定,任意一个二进制浮点数V都可以表示成以下形式:
V = ( − 1 ) S ∗ M ∗ 2 E V = (-1)^S*M*2^E V=(1)SM2E
其中:

  • ( − 1 ) S (-1)^S (1)S用于表示符号, S S S 的值为 01
  • M M M表有效数据,且 1 ≤ M < 2 1\le M < 2 1M<2
  • 2 E 2^E 2E,表指数,类似科学计数法中的 1 0 x 10^x 10x

下面举几个简单的例子:

  • V = 5.5:
    5.5 = 4 + 1 + 0.5 = 2 2 + 2 0 + 2 − 1 5.5=4+1+0.5=2^2+2^0+2^{-1} 5.5=4+1+0.5=22+20+21,因此,V二进制表示形式为101.1
    V = ( − 1 ) 0 ∗ 1.011 ∗ 2 2 V = (-1)^0*1.011*2^2 V=(1)01.01122
    S = 0;M = 1.011 ;E = 2

  • V = -0.5:
    − 0.5 = − 2 − 1 -0.5=-2^{-1} 0.5=21,因此,V二进制表示形式为-0.1
    V = ( − 1 ) 1 ∗ 1.0 ∗ 2 − 1 V = (-1)^1*1.0*2^{-1} V=(1)11.021
    S = 1;M = 1.0 ;E = -1

2.2存储格式

当规定了怎么表示浮点数后,IEEE754又规定了浮点数的具体存储格式:

  • 单精度浮点数:使用32个比特存储。
    其中,符号位 ( S ) 占第1个比特位,指数位 ( E ) 占接下来的8个比特位,尾数位 ( M )占最后的23个比特位。
  • 双精度浮点数:使用64个比特存储。
    其中,符号位 ( S ) 占第1个比特位,指数位 ( E ) 占接下来的11个比特位,尾数位 ( M )占最后的52个比特位。
    在这里插入图片描述

存储细节

上面的图中清晰的给出了 S S S M M M E E E的位置,但是对于 M M M E E E的具体存储过程,IEEE754还有一些特殊的规定。
M
前面说过: M M M表有效数据,且 1 ≤ M < 2 1\le M < 2 1M<2
即对于任意的 M M M,都可表示为1.xxx,因此,IEEE754规定,在存储的过程中,不会存储小数点前面的1,而只存储小数点后的数位。
例如:float n = 5.5;时, M M M1.011,在存储时,则只保留011

E
首先需要注意的是, E E E是一个无符号整数。
这意味着,在单精度浮点数中, E E E8位,它的取值范围是0~255 ;在双精度浮点数中, E E E11位,它的取值范围是0~2047
而为了表示 E E E为负数的情况,IEEE754规定,在 E E E存入内存前必须加上一个中间数:8位的是127,11位的是1023
例如:float n = 5.5;时, E E E为2,在存储时,必须保存为2+127=129,即1000 0001。

取出

在取出时,可大致根据 E E E的不同分为三种情况:
E不为全0或全1
取出时需将 E E E减去一个中间数得到原始值,再带入公式计算。
E为全0
表示正/负0。
E为全1
表示正/负无穷。

3.相关代码的解释

回到开头:

int n = 5.5;

n被赋值为5,此时是整型:
在这里插入图片描述


float* p = (float*)&n;

使用指向浮点型的指针p指向n,此时,*p为浮点型:
在这里插入图片描述


printf("%d\n", n);
printf("%f\n", *p);

第一次打印,n为整型,打印的是整型,结果为:

5

第二次打印,*p为浮点型,打印的是浮点型,由于E为全0,表示的值为0,结果为:

0.000000

*p = 5.5;

*p被赋值为5.5,由于*p是浮点型,因此按浮点数的方式存储:
在这里插入图片描述


printf("%d\n", n);
printf("%f\n", *p);

第三次打印,将n看做整数打印,运行结果如下:

1085276160

在这里插入图片描述
第四次打印,打印浮点数,结果为:

5.500000


希望本篇文章对你有所帮助!并激发你进一步探索C语言的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值