数据在内存中的存储

Posted zsQgqdsd1002

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据在内存中的存储相关的知识,希望对你有一定的参考价值。

数据在内存中的存储


前言

我们知道,创建一个变量就要在内存中开辟一块空间,开辟的这块空间的大小是取决于你数据类型的,变量又可以分为很多类,有整型变量,有浮点型变量,有字符型变量等等,我们今天所要分析的就是整型和浮点型在内存中的存储方式。


提示:以下是本篇文章正文内容,下面案例可供参考

一.原码,反码,补码

我们首先来了解一下原码,反码,补码三个概念。他们三个的表示方法有两个共同的地方,就是都是分为符号位数值位两方面。符号位都是用0来表示正数,1来表示负数。而数值位方面则是各有不同,我们下来一一介绍。

原码就是数字本身的样子,即就是把一个数字分解成32位得到的数值。对于正数而言,这32位都是数值位,而对于负数而言,第一位是符号位1,其余的也不是数值位,这些我们一会会讲到。

反码就是在原码的基础上,符号位不变,其余位全部取反得到的结果。

补码则是在反码的基础之上加1就可以了,负数在计算机中的存储通常是以补码形式存在的。而这也就是为什么负数的原码符号位之后不是数值位的原因。

二、整型数据在内存中的存储

我们知道,数据在计算机中的存储都是由二进制来完成的,对于整型变量来说,一个数字可以被分解为32位,由32个0和1组成,其可以表示的范围在无符号的情况下大概是0~42亿9千万,在有符号的情况下则大概是-21亿~21亿。

需要注意的是,对于正数而言,它的原码,反码,补码都相同;而对于负数而言,它的原码,反码,补码就需要以上面所讲述的形式进行换算,对于整型数据来说,它们在计算机中的存储都是用补码的形式进行存储的。为什么呢?

因为使用补码的话可以将符号位和数值位统一进行处理,由于我们的计算机智能进行加法运算,所以用这种形式来储存数据在计算起来也会非常的方便。我们来举个例子:

#include<stdio.h>
int main()

	int a = 1;
	int b = 1;
	printf("%d", a - b);
	return 0;

前面说到计算机是只有加法没有减法的,所以程序中虽然写的是a - b但是在实际的运算中计算机所运算的会是a + (-b),那么计算机会如何进行计算呢?我们一起来看一下:

首先计算机会拿到1的原码,因为正数的原反补都相同,即此时把1转为:

				0000 0000 0000 0000 0000 0000 0000 0001

其次计算机会拿到-1的原码,但是由于数据在计算机中的存储都是以补码形式存在的,所以这个时候计算机会先拿到其反码在将其转为补码形式,即就是:

			1000 0000 0000 0000 0000 0000 0000 0001
取反--->    1111 1111 1111 1111 1111 1111 1111 1110
取补--->    1111 1111 1111 1111 1111 1111 1111 1111

得到了-1的补码之后,将-1的补码与1的补码进行相加操作:

			0000 0000 0000 0000 0000 0000 0000 0001
	+		1111 1111 1111 1111 1111 1111 1111 1111
	=	   10000 0000 0000 0000 0000 0000 0000 0000		

由于int类型只能存储32位,那么现在1的位置处于第33位,舍弃之,最后得到的就是32位0,也就是数字0

三、浮点型数据在内存中的存储

1.思考

我们来看这样一段代码:

int main()

	int a = 1;
	float* p = (float*)&a;//将a强制转换为float类型
	printf("%d\\n", a);
	printf("%f\\n", *p);
	return 0;

此时程序会输出什么?第一行是1,第二行是1.000000吗?我们一个编译执行来看一下:

这是为什么呢?我们下面来慢慢介绍:

2.答疑解惑

根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式:

(-1)^S*M*2^E
其中(-1)^s表示符号位,当S = 0,V为正数;当S = 1,V为负数。
M表示有效数字,这个数字大于等于1且小于2。
2^E表示数位

我们举例来说,比方说十进制的6.0,写成二进制位就是110.0相当于1.10 * 2^2。那么我们根据上面的格式可以得到
S = 0,M = 1.10,E = 2

同样的,十进制中的-6.0,写成二进制位就是-110.0相当于-1.10*2^2,根据上面的格式相可以得到
S = 1, M = 1.10, E = 2

根据IEEE 754的规定:
对于32位的浮点数而言,最高位的为符号位,接着的8位数字是指数位,最后的23位则为有效数字

如图所示,这就是单精度浮点数的各个位详情。

那么对于双精度浮点数来说,大体也是这个规律,只是我们知道双精度浮点数的大小为8个字节,所以在这个地方S,M,E就有一点点不同的地方了,此时的S仍旧是第一位表示符号,中间的E则会变成11位,而最后的52位则都是有效数字位M。

3.M和E

我们下面来说一说M和E,IEEE 754在对M和E这方面还有一些特殊的规定,我们来先说一说M:

(1)M

我们前面提到过M的取值范围是1到2之间,也就是说M的书写形式可以写为1.xxxxxx,其中后面的六个x便代表的是小数部分。根据规定,在计算机内部保存M的时候,默认M的第一位是1,所以可以被舍去然后只保留后面六个x的部分。我们比方说是1.01,只保存01这个部分,等到读取的时候再把这个1拿出来,这样做可以节省一位有效数字,以float类型的数据为例,M只能保存23位有效数字,而当我们省去这个1的时候,他就可以保留24位有效数字。

(2)E

下面我们再来介绍一下指数位的E:

E的存储

首先我们要知道指数位的E它的类型是unsigned int,即就是无符号的整数类型,我们知道E是8位或者11位,这取决于数据类型是float类型还是double类型。如果是float类型,它能表示的范围就是0~255之间;如果是double类型,那么它能表示的范围就是0~2047。但是我们知道,指数位是可以为负数的,所以在IEEE 754的规定下,存入内存时的E需要加上一个中间值,对于8位的E来说这个中间值是127,而对于11位的E来说这个中间值则是1023。我们来举个例子:

例如2^10,我们知道E的值为10,如果以float类型去存储它,存入E的时候要存入的不能是10的二进制00000110,而是10 + 127 = 137,即就是10000101

E的取出

将E从计算机中取出的情况分为三种情况:

E不全是0或者E不全是1:

这个时候,浮点数会让指数E的值减去127或1023(取决于类型),得到E的真实值,再将有效数字M前加上1

E全是0

这个时候浮点数的指数E就等于0 - 127或者0 - 1023,得到E的真实值,但是这个时候有效数字M前不会加上1,而是变成0.xxxxxx的小数。这样做是为了表示很接近0的很小的数字(可正可负)

E全是1

这个时候如果有效数字M全是0,就表示±∞,这取决于符号位


总结

了解数据的存储方式在我们的学习中有很重要的作用,所以希望大家可以通过我的文章获得些许的帮助。以上就是我今天想分享给大家的内容,希望可以给大家带来帮助,如果有什么错误的地方或者可以改进的地方,欢迎大佬联系我。

以上是关于数据在内存中的存储的主要内容,如果未能解决你的问题,请参考以下文章

[算法]浮点数在内存中的存储方式

浮点型数据在内存中的存储

请问浮点型数据在计算机是怎么存储的

floatdouble的精度范围,在内存中的存储方式

C语言学习 -- 整型与浮点型在内存中的存储

计算机中的原码,反码,补码,以及他们在内存中的存储形式。