数据在内存中的存储

整型在内存中的存储

在计算机中,整型数值都是用补码来表示和存储的,可以通过代码来了解。
int main()
{
	int a = 20;
	int b = -10;
	return 0;
}

首先我们来分析一下
20是正数,原码,反码,补码都一样
原码是00000000 00000000 00000000 00010100
反码是00000000 00000000 00000000 00010100
补码是00000000 00000000 00000000 00010100
转换成十六进制是00 00 00 14
-10是负数
原码是10000000 00000000 00000000 00001010
反码是11111111 11111111 11111111 11110101
补码是11111111 11111111 11111111 11110110
转换成十六进制是ff ff ff f6

接下来我们运行调试分别看一下a和b的内存
在这里插入图片描述
在这里插入图片描述

大端存储和小端存储

可以看到和我们推理出来的是反过来了,这就是小端存储,也叫小端字节存储,同样的也有大端存储,也叫大端字节存储。是数据在电脑上存储的字节顺序。
大端存储(大端字节序存储):是指高位字节数据放在低地址处
小端存储(小端字节序存储):是指低位字节数据放在低地址处

举个例子:
假设一个数据的地址为0x 22 44 66 88
如果是大端存储,那么就是22 44 66 88
如果是小端存储,那么就是88 66 44 22

我们还可以通过代码来判断是大端存储还是小端存储
思路:从表面上来看大端存储和小端存储的一个区别是第一个字节的不同,所以我们可以取出第一 个字节进行分析,而char类型每次可以操作一个字节

int main()
{
	int a = 1;
	char* p = (char*)&a;//取出a的第一个字节
	if (*p == 1)
	{
		printf("小端存储");
	}
	else
	{
		printf("大端存储");
	}
	return 0;
}

也可以写成函数的形式

int check_sys()//如果是小端存储返回1,大端存储返回0
{
	int a = 1;
	char* p = (char*)&a;
	if (*p == 1)
		return 1;
	else
		return 0;
}
int main()
{
	int ret = check_sys();
	if(ret==1)
		printf("小端存储");
	else
		printf("大端存储");
	return 0;
}

浮点型在内存中的存储

先看一段代码

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;

	printf("n的值为:%d\n",n);
	printf("*pfloat的值为:%f\n",*pFloat);

	*pFloat = 9.0;
	printf("n的值为:%d\n", n);
	printf("*pfloat的值为:%f\n", *pFloat);
	return 0;
}

正常来说,打印的结果应该都是9或者9.000000之类的,然而事实打印出来的是这样的
在这里插入图片描述
这就说明了浮点型的存储和整型是完全不一样的
所以在学习浮点型的存储时我们需要知道几个点
1.浮点数没有原码反码补码的概念
2.所有的浮点数v都可以写成该形式v=(-1)^s * M * 2^E,其中S是0或1
3.对于32位的浮点数(单精度),最高的1位是S,接着的8位是E,剩下的23位是M
4.对于64位的浮点数(双精度),最高的1位是S,接着的11位是E,剩下的52位是M
5.M只存小数点后的数字

对于E来说有几种情况
1.E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1
2.E全为0
这时,浮点数的指数E等于1 - 127(或者1 - 1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数
3.E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

乍一看有点混乱,我们可以通过代码分析

int main()
{
	float f = 5.5f;
	return 0;
}

十进制的5.5转换成二进制就是101.1
也就是1.011*2^2
也就是(-1)^0 * 1.011 * 2^2
在这里插入图片描述
其中不难看出S=0,E=2,M=1.011
在这里插入图片描述
0 10000001 01100000000000000000000
0100 0000 1011 0000 0000 0000 0000 0000
转换成十六进制就是40 b0 00 00
通过调试我们可以看见f的内存如下
在这里插入图片描述
再看一段类似的代码加深理解

int main()
{
	float f = 9.0f;
	//1001.0
	//1.001*2^3
	//(-1)^0*1.011*2^2
	//S=0,M=1.001,E=3
	//0 10000010 00100000000000000000000
	//0100 0001 0001 0000 0000 0000 0000 0000
	//41 10 00 00
	return 0;
}

分析和上一段代码差不多,调试的结果如下
在这里插入图片描述

学习到现在我们来回看一下一开始的代码,看看能否理解

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;

	printf("n的值为:%d\n",n);
	printf("*pfloat的值为:%f\n",*pFloat);

	*pFloat = 9.0;
	printf("n的值为:%d\n", n);
	printf("*pfloat的值为:%f\n", *pFloat);
	return 0;

对于第一个printf和第四个printf的打印应该没什么问题,我们来看看第二个和第三个。

首先n=9是一个整型,而整型的存储形式是二进制的补码,而正数的原反补码都一样,为00000000 00000000 00000000 00001001,当n的地址被取出来交给pfloat后,pfloat就指向该二进制序列,由于pfloat的类型为浮点型,所以在它看来该序列是
0 0000000 000000000000000000001001,分别对应S,E,M,我们可以发现E为全0,即
在这里插入图片描述
所以我们可以把它还原成(-1)^0 * 0.000000000000000000001001 * 2^-126是一个特别小的数,由于小数点后只打印六位,所以打印0.000000
对于在这里插入图片描述
由于它是一个浮点型,我们先把它转换成科学计数法,由于上边有一样的,所以这里直接写出,为(-1)^0 * 1.011 * 2^2,从中可以看出S=0, E=3,M=1.001,对应的序列为
0 10000010 00100000000000000000000,由于n是一个整数,所以在它看来内存中存储的是整数,而该序列就是该数的补码,又因为%d表示有符号并且该序列第一位是0表示正数,而正数的原码和补码是一样的,所以该序列对应的就是1091567616,刚好和我们程序运行的结果一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值