C语言中数据在内存中的存储详解(探索计算机内存中数据处理)

前言:我们编写程序时,都是用C语言编译器给我们提供好的内置数据类型使用,那么计算机底层如何对这些数据进行区分以及处理的呢?下面进行揭晓。

1.整数在内存中的存储机制

我们知道整数的二进制表示方法有三种,分别是原码、反码和补码。
它又可以细分为有符号整数和无符号整数。有符号的整数,三种表示方式都由两部分组成:符号位和数值位,二进制的最高位被当作是符号位(0表正数,1表负数),剩余位都是数值位。

  • 正整数的原码、反码、补码都相同。
  • 负整数的三种表示方法都是不一样的。

原码:将数值按正负数的形式直接写成二进制的得到的就是原码。
反码·:原码的符号位不变,其余位按位取反即可得到反码。
补码:对反码+1得到的就是补码。
对于整型,数据在内存中的存放的其实是它的补码。

原因如下:

在计算机系统中,统一使用补码来表示数值,因为这样可以使加法和减法操作统一,从而简化计算机的硬件设计(CPU只有加法器,另外,补码与原码相互转换,其运算过程相同,不需要额外的硬件电路)。

2.浮点数在内存中的存储

生活中常见的浮点数有:3.1415926、2E10等。C语言中的浮点数类型包括:floatdoublelong double类型。
浮点数的表示范围在:头文件float.h中定义。
首先看一段代码:

#include <stdio.h>
//浮点数在内存中的存储
int main()
{
	int i = 10;
	float* pf = (float*)&i;
	printf("i = %d\n", i);
	printf("*pf = %f\n", *pf);

	*pf = 10.0;
	printf("i = %d\n", i);
	printf("*pf = %f\n", *pf);

	return 0;
}

看上述代码,同一个数以不同类型解析会是什么样的结果呢?难道是:

i = 10 ?
*pf = 10.0?
i = 10?
*pf = 10.0?

如果你是这么想的话,那么恭喜你只对了一半。请看运行结果:
在这里插入图片描述

通过观察运行结果可以得出一个结论 - 整数和浮点数在内存中的存储是不一样的

2.2 浮点数在内存的存储

分析:浮点数在计算机内部是如何表示的。
国际标志IEEE(电气和电子工程协会)754规定,任意一个二进制浮点数V可以表示成下面的形式:
在这里插入图片描述

比如:十进制的10.5,写成二进制是1010.1,科学计数法表示:1.0101 * 2^3
使用V的格式来说明的话:S = 0,M = 1.0101,E = 3.

IEEE 754规定了:
对于32位的浮点数,最高的一位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。
对于64位的浮点数,最高的一个为存储符号位S,接着的11位存储指针E,剩下的52位存储有效数字M。

在这里插入图片描述
分析:

#include <stdio.h>
int main()
{
	//10.5
	float f = 10.5f;
	//10.5 -- 十进制
	//1010.1 -- 二进制
	//(-1)^0 * 1.0101 * 2^3
	//S = 0
	//M = 1.0101
	//E = 3
	//3 + 127 = 130
	//0100 0001 0010 1000 0000 0000 0000 0000 - 浮点数(float)在内存中的存储
	//41 28 00 00 -- 16进制
	return 0;
}

调试结果:

在这里插入图片描述
需要注意的是:举例不要举特殊值,比如:3.1415926……

2.3 浮点数存储过程

IEEE 754 对有效数M和指数E有一些特殊规定。
我们知道M的范围是1≤M<2,也就是M可以写成1.xxxxx的形式,其中xxxx表示小数部分。IEEE 754规定,计算机内部存储M时,默认这个数的第一位是1,因此把第一位数给省略,只保留后面的小数部分。如1.0101,只保留0101,等到读取时再把第一位的1加上。这种做法的目的是节省一位有效位。拿32位浮点数举例,M只有23位有效数字,将第一位的1舍去之后,便可以保留24有效数字。

指针E的情况略复杂些

E是一个无符号整数(unsigned int)
表示如果E为8位时,它的取值范围是0~255;如果E为11位时,它的取值范围是0 ~ 2047.IEEE 745规定,存入内存时E的真实值必须要加上一个偏移量,对于8位的E,它的偏移量是127;对于11位的E,它的偏移量是1023。
例如:
2^10的E是10,所以保存32位浮点数时,必须保存成10+127 = 137,二进制为10001001.

2.4 浮点数的读取过程

指数E从内存中取出可分为三种情况:

情况一:E不全为0或者不全为1
浮点数的计算规则:指数E的计算值 - 127(或1023),得到实际值(真实值),再将第一位的1加到M前。

举例:
0.75的二进制形式为0100 1011,由于规定正数部分必须为1,即将小数点右移两位,得到1.001011*2^(-2),其阶码为-2+127 = 125,表示为01111101,而尾数1.0去掉整数部分为0,补齐0到23位,则可表示为:

0 01111101 000000000000000000

情况二:E为全0
此时,浮点的指数E等于1~127(或1 ~ 1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxx的小数。目的是为了表示±0,以及接近0的很小的数字。

0 00000000 00100000000000000000000

情况三:E为全1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位S)。

0 11111111 00100000000000000000000

2.5 代码解析

回看这段代码:

#include <stdio.h>
int main()
{
	int i = 10;
	float* pf = (float*)&i;
	printf("i = %d\n", i);
	printf("*pf = %f\n", *pf);

	*pf = 10.0;
	printf("i = %d\n", i);
	printf("*pf = %f\n", *pf);

	return 0;
}

分析:
在这里插入图片描述

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值