我们已经学到的数据类型有浮点形和整形那么它们是怎么存储的呢?
目录
-
整形
整形成员
首先我们来看一下整形家族有哪些,整形家族有:int 、long 、long long、其实char也是整形的一员,其代表所表示的字符的ASCII码值。
存储方式
看一下以下代码:
int a = 10;
char b = 10;
这里由10是一个整数,代表一个int类型的数据,换算成二进制数则有32位数,如下:
000000000000000000000000000001010
然后要存入变量a对应的内存块,这里有一个规则,存入的时候要以补码的形式存入
源码反码补码
源码反码补码的关系
源码变成反码,符号位不变其它位按位取反。反码变成补码,反码加一就是补码。
为什么要用到补码这个东西,它的优势何在?
这里插一句题外话:由于处理器中只有加法运算器,故当涉及减法或者负数加减的时候,这个时候使用补码就有优势了,首先我们怎么去理解补码这个东西呢?看一下以下的图
以上是char类型的(八位)的补码对应的值,如用补码进行计算1-2,则只要用加法器进行加上1和-2分别对应的补码就可以,即
00000001+11111110,得到11111111,在换成源码就对应了-1.由此可见利用补码的优势。(这里用时钟来理解也可以,本质上是一样的)
好,回归正题。
上面讲到要用补码来进行存储,但是这里会遇到一个问题,就是10这个数字是int类型的默认为其有三十二位(000000000000000000000000000001010),但是char类型的内存容量只有八个bite也就是说只能容下八位,故会截断后存储(00001010)。
整形数据的使用
整形数据的使用,int 类型当然是按存的补码转换成源码来用,但是如果是char类型的时候,会有整形提升这个东西,那什么是整形提升呢?
整形提升
是什么
整形提升简单来说就是由于处理器中的运算器有三十二位,在使用的数据类型少于三十二位的时候会自动变成三十二位,这里一般对象为char或者short类型的变量。
怎么提升呢?
整型提升的一般规则为:首先先判断是否为有符号位(即是否为signed类型),如果是unsigned则在前面补上0,补到32位为止,如果是signed的话就要继续判断符号位,如果符号位为1则前面不上1补到32位,如果符号位为0则前面补上0补到32位。
哪种情况提升呢?
一般情况为,加减乘除,这样的算数运算(如+a,-a,1*a,1/a),位运算(>>a,<<a),关系运算(>a,<a,<=,>=,==),使用函数printf("%d",m);这些时候就会进行整形提升,让短整型变成int 类型的长度。
例子:
#include<stdio.h>
int main()
{
char m = -1;
printf("%d\n",sizeof(m));
printf("%d\n", sizeof(+m));
printf("%d\n", sizeof(-m));
printf("%d\n", sizeof((char)1 * m));
printf("%d\n", sizeof((char)1/m));
return 0;
}
这里就发现确实有这么一回事,让我们继续看一眼下面的例子:
#include<stdio.h>
int main()
{
char m = -1;
printf("%u\n",m);
printf("%d",m);
return 0;
}
这个是为什么呢?
我们来看看,首先这里是会整型提升的,然后我们在进行分析,首先,-1对应的int 类型的反码为:
11111111111111111111111111111111
存入char之后,截断成:
11111111
在使用整形打印的时候,会发生整形提升,由于本编译器中char为signed类型的,故提升为:
11111111111111111111111111111111
其对应的源码为:
1000000000000000000000000001
这个时候看是把它看成什么,如果是有符号数(”%d“)则为-1,如果是无符号数(”%u“)则为一个很大的数(最高位不是符号位)。
我们继续看下面的例子:
#include<stdio.h>
int main()
{
char m = -1;
unsigned char n = -1;
printf("%u\n",m);
printf("%u\n",n);
printf("%d\n",m);
printf("%d\n",n);
return 0;
}
这里我们分析一下,unsigned char类型,同样,存入-1的时候都是一样的截断,故存入的数据为:11111111
在用无符号数打印时,同样发生整形提升,由于是unsigned类型的,故前面补上0,得到:
000000000000000000000000111111111(由于是正的,故源码反码补码相同)
这里用无符号数打印的话,就是255,如果用有符号数打印的话,还是255。
到这里整形的存储和使用就讲完了,接下来就是浮点数的存储和使用了。
-
浮点型
浮点型成员
浮点数的成员有:float ,double ,long double
存储方式
浮点数的存储方式与整形完全不同。
要了解浮点数的存储方式,我们先要了解科学计数法,对于十进制的科学计数法我们很熟悉,如31415.926用科学计数法表示就是(-1)^0*3.1415926*10^4,好这样我们类比到二进制的科学计数法,100101.1001,这里我们可以表示为:(-1)^0*1.001011001*2^5,这里的参数(注意这里有一个点,就是由于有效数字前面总会是1,故省去不写,剩余的存入,存入提供的空间为23,不足时后面补0)1.001011001,0还有5就是浮点数类型要存储的数据。IEEE754标准提供了存储的方式,float的存储方式为:
前面第一位就是-1的指数,中间的八位为2的指数位,后面为有效数字。
这里有一个例子:
#include<stdio.h>
int main()
{
int a = 10;
float* p = (float*)&a;
printf("%d\n",a);
printf("%f\n",*p);
*p = 10.0;
printf("%f\n",*p);
printf("%d",a);
return 0;
}
第一个毋庸置疑,第二个我们来看一下:
由于a变量对应的内存块中存入的是:00000000000000000000000000001001
强制类型转换成float*并且解引用后,会把他当成浮点数来看,那么为什么是0呢?这里就涉及浮点数的存储和使用了。
存储补充
存进去的时侯,如果2对应的指数为负数的话,那么这里就无法直接存储了,因为这个只能存储正数,故IEEE754规定,2对应的指数存入的值等于真实值加上127.
浮点数的使用
浮点数的使用,按照IEEE754的规定来将浮点数对应的内存块取出来,然后转化成对应的数值,这里有两个值得注意的点,由于有效数字对应再存入的时候少了第一位1,故看的时候要加上,还有,这里的2的指数这里要分情况看,如果是0的话,结果就是0(由于减去127,这里是一个很小的数字,由于表示的位数有限,则直接为0)如果全为一的话,则是无穷大(同样的道理),如果是其他的数的时候就减去127,得到指数部分。
故上面
00000000000000000000000000001001
这里2的指数部分全为0,则结果为0
利用指针将a改为10.0时,用浮点数指针打印出10.0这个没问题,但是用整形打印出来就变成了一个很大的数,为什么?
在让我们分析一下,
10.0这里可以写成科学计数法:(-1)^0*1.0*2^1
这里存入的数据为0,1+127,0
即010000000000000000000000000
发现转换成十进制就是上面的数。