数据在内存中的存储

关于整数在内存中的存储我还有几个题没有给完,下面来一起看一下:

补充一点%x是以和十六进制打印整数的。

#include <stdio.h>
//X86
int main()
{
 int a[4] = { 1, 2, 3, 4 };
 int *ptr1 = (int *)(&a + 1);
 int *ptr2 = (int *)((int)a + 1);
 printf("%x,%x", ptr1[-1], *ptr2);
 return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//x86环境 小端存储
int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);//&a是取出了整个数组的地址,+1就直接跳过了整个数组,&a的类型是这样的int(*)[4]
//这时候进行强制类型转换转换成int*,这时候ptr1就指向4的后面的地址。

	int* ptr2 = (int*)((int)a + 1);//难的在这一个,首先a还是首元素的地址,我要把他强制类型转换成int型,就只是整数,那他+1加的是多少?
//答案是就是+1这里要说明一个问题:
//指针+1:要看一下指针是什么类型的,如果是int型的就是+4如果是char型的就是+1。
//整数+1:就是+1
//假如说a的地址是0x0012ff40强制类型转换成整型了+1结果就是0x0012ff41,就是这么简单
//那么好,现在我们在继续讲解这个题,当我们在把(int)a+1强制类型转化int*之后,这时候这个ptr2指向的是起始地址的一个字节之后的地址,
//但是一个整数就有四个字节
//因为是 小端存储 所以就是这样01000000 02000000 03000000 04000000本来a的位置就在01前面,加完之后就在01后面了这时候ptr2就是指向的01之后的地址
//又因为ptr2是整形指针他指向后面的4个字节,要对ptr2进行解引用就是00 00 00 02因为是小端存储,展示出来就是0x02000000
	printf("%x,%x", ptr1[-1], *ptr2);
//这里的ptr1[-1]就是*(ptr1-1)也就是*(ptr1+ -1),这时ptr1是指向四后面的地址,但是这时候进行-1就是指向3后面的位置,就是4的地址,这时候解引用取出的就是4.
	return 0;
}

OK了现在习题就完了,这个题价值挺大的,我也是挺费劲的讲解出来。如果有什么不对的地方希望大家能够提出来。

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

常见的浮点数:3.14159,1E10等,浮点数包括:float,double,long,double类型。

浮点数表示的范围:float.h中的定义。        

在讲解浮点数在内存中的存储之前,我们先来看一串代码,有助于更好的理解:

#include <stdio.h>
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;
}

我们考虑一下这个会输出的什么结果?我一开始以为会是9 9.0 9 9.0但是结果不对,所以这里我们要考虑一下是不是整数与浮点数在内存中存储的方式不一样?那么下面我会进行讲解:

1.1浮点数的存储

上面代码中num和*pFloat在在内存中明明是同一个数,为什么浮点数和整数的解读结果会这么大?

想要理解为什么有整个么大的差别,那么这里我们就先要了解浮点数在计算机内部的表示方法:

不懂的话没有关系,我们举个例子:

一个十进制的5.0写成二进制是101.0 这时候这个二进制数字就可以表示为1.01×2^2,按照上面的格式我们可以得出S = 0,M = 1.01,E = 2。

这里的2的E次方怎么理解呢?假如说是一个十进制的是101那么这个数写成科学计数法就是1.01×10^2但是上面的是二进制数要写成科学计数法所以就是1.01×2^2.

那在给一个例子 -5.0 这个数写成二进制是-101.0相当于-1.01×2^2,那么S = 1, M = 1.01, E = 2

补充:这里我再说一下关于十进制的浮点数怎么转换成二进制?上面的都太简单这里我们给5.5,那么大家会以为是101.101但是不是这样的,我来说一下二进制小数点后面的转换规则:

看到了没有小数点后面的是负次方 ,就是这样的101.1。写成科学计数法就是1.011*2^2

所以呢,从这些讲解可以看出来 ,浮点数的存储其实就是S.M.E的相关值。这是规定的,下面我就来说一下是怎么进行规定的:

1.1.1浮点数存的过程 

IEEE 754 对有效数字M和指数E,还有一些特别规定:

前面说过,1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx 表示小数部分。IEEE 754 规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如:保存1.01的时候,只保存01等到读取的时候,再把第一位的1加上去。这样做的目的:是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
至于指数E,情况就比较复杂首先,E为一个无符号整数(unsignedint)(这里直接把E当作无符号整数)
这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的(就像0.5他的二进制是0.1,写成科学计数法就是(-1)^0*1.0*2^-1 S = 0,M = 1.0 E = -1),所以IEEE754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001,最后把这8位存到八个比特位里面去。

那我们给出一串代码来进行实验:

int main()
{
  float f = 5.5f
//5.5写成科学计数法的形式是(-1)^0*1.011*2^2
//s = 0
//M = 1.011
//E = 2
//2+127 = 129
//那么他的存储就是0 10000001 011 00000000000000000000
                S    129   先把M的整数部分去掉写上011如果不够的话就用0来进行补充
//如果看着别扭我们还可以转换成十六进制的形式
//0100 0000 1011 0000 0000 0000 0000 0000
//40 B0 00 00就是这样。
//又因为是小端存放,所以在内存中是这样的00 00 B0 40
return 0;
}
这里有一点需要注意,在举例的时候不要举特殊数字比如:3.14
1.1.2浮点数取得过程 

指数E从内存中取出还可以再分成三种情况:

指数E不全为0或不全为1

这时,浮点数就要采用下面的规则表示,即指数E的计算值减去127或者1023,得到真实值,再将有效数字M前加上第一位的1.

就想这样:0.5的二进制形式为0.1,由于规定整数部分必须为1,即讲小数点右移一位,则为1.0*2^(-1)其阶码就是-1+127(中间值) = 126表示为011111110,而尾数1.0去掉整数部分为0,补齐0到23为000000000000000000000000那么他的二进制表示形式就是这样的:

0 01111110 00000000000000000000000

E全为0 

E全为说明E+127--->0那么E== -127那么这个数就会很小1.xxxx*2^-127已经无限接近于0了

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxxx的小数。这样做是为了表示+-0,以及接近于0的很小的数字。

0 00000000 00100000000000000000000

 E全为1

这时,如果有效数字M全为0,表示+-无穷大(正负取决于符号位s)

0 11111111 00010000000000000000000

1.2题目解析

再让我们回到之前的题目:

#include <stdio.h>
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;
}

先看第一环节:为什么9还原成浮点数,就成了0.000000?

9以整数的形式存储在内存中得到如下二进制序列:

0000 0000 0000 0000 0000 0000 0000 1001

这时:我们要直到整数和浮点数在内存中的存储方式是不一样的,上面给的是整数的二进制序列,我们把整数强制类型转换成了浮点数,他在内存中的存储的还是这个序列,但是我们读取的就不应该按照二进制来进行读取。

首先我们将9的二进制序列按照浮点数的形式拆分,得到第一位符号位s = 0,后面的8位的指数E = 00000000

最后23位的有效数字M = 000 0000 0000 0000 0000 1001。

由于指数全为0,所以符合E为全0的情况。因此,浮点数V就写成:

V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

显然V就是一个无限接近0的正数,所以用十进制小数表示就是0.000000

那么再来看一下第二个环节:

好了,关于浮点数的表示规则,就说到这吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值