C语言进阶知识(二)

数据在内存中的储存

1.浮点型在内存中的储存

首先,我们先来了解浮点数的概念,浮点数指数学中的小数,浮点指的是可以按照不同的权重定义小数,如1.23*10^3或12.3*10^3,此时小数点的位置在浮动,由此引申出浮点数的概念。

我们先来看一段代码:

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;
}

C语言进阶知识(二)_第1张图片

我们期望出现的结果是9;9.0;9;9.0

但实际运行结果却不是这样的,我们以整型存入n,取出n的地址后强制类型转换,指针pFloat将指向强制类型转换后的float型变量n,然后我们使用%f打印储存的pFloat,发现结果也不是我们想要的9.0;后我们打印整型%d,但此时应该是浮点型的n,若整型浮点型储存方式相同,那么结果应该为9;可根据代码实际运行结果,我们发现:整型和浮点型在内存中的表示方式并不相同。

那么浮点型在内存中究竟如何储存呢?

根据规定,我们知道任意一个二进制浮点数V可表示为以下形式:

V=(-1)^S*M*2^E;(-1)*S表示符号位,S为0,V为正数;S为1,V为负数。

M表示有效数字,取值为【1,2);2^E表示指数位。

以十进制5.5举例,转化为二进制位101.1,转化为标准型V为(-1)^0*1.011*2^2;此时S=0;M=1.011;E=2;

对于32位浮点数,最高的一位是符号位S,接着的8位是指数E,剩下的23位是有效数字M。

对于64位浮点数,最高的一位是符号位S,接着的11位是指数E,剩下的52位是有效数字M。

对于M,我们有另类规定,M可写为1.xxxxxx,我们在储存时候省略1,只保存xxxxxx,这样的目的是增加有效数字的位数,如32位,有效数字可增加为24位。

对于E,我们认为它为无符号整数,但实际上我们的E存在负值,如果E为8位,取值范围为0-255;如果E为11位,取值范围为0-2047;所以为了可以存入负数,我们在存入E时候,为其加一个中间值,对8位E,中间值是127;对11位E,中间值是1023。

2.实际储存方式

上面我们简述了浮点数在内存中的储存,接下来我们以开篇代码的题目为例,解释为什么在VS2022会跑出这样的结果,并验证在内存中浮点数是否按照我们所说的进行储存。

int main()
{
	int n = 9;
	//0 00000000 00000000000000000001001
	//S    E              M
	//0    0+127(中间值)  0.00000000000000000001001
	float* pFloat = (float*)&n;
	printf("n的值为:%d\n", n);//9
	printf("*pFloat的值为:%f\n", *pFloat);//0.000000
	*pFloat = 9.0;
	//1001.0
	//1.001*2^3
	//S=0 M=1.001 E=3
	//0 10000010 00100000000000000000000
	printf("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

 在此例中,我们将M转换时前面并没有添加1,而是添加0,这是因为E全为0,这说明原来的E应该是-127,2^(-127)一定是个极小的数,至少要比1小很多,若我们添加为1相当于增大原来的数字,误差过大。所以添补数字为0;而我们以%f打印:pFloat,由于小数点后取值,所以前面的数都是0;而当我们以%d打印时候,首先看符号位为0是正数,回顾进阶知识(一),我们知道正数的原码补码反码相同,所以我们打印出来的就是这串2进制转化为16进制后的数字。

你可能感兴趣的:(C语言进阶知识,c语言,开发语言,笔记)