之前介绍过C语言内置的数据类型,这里重点介绍在内存中这些数据类型是如何存储的
目录
1.整形的存储
1.1原码、反码、补码
1.2大小端
2.浮点数
2.1S、M、E的存储细节
1.整形的存储
1.1原码、反码、补码
char、short、int、long 和long long,不管是有符号还是无符号,它们在内存中存储的二进制表示有3种表示形式,即原码、反码和补码
整形在内存中以补码的形式存储,打印的时候以原码的形式打印
非负整数的原码、反码和补码是相同的,负整数的原码符号位不变,其它位按位取反得反码,反码+1得补码
无符号的整形没有符号位
那么为什么整形存储是补码,而打印的时候是原码?
来看一下下面的式子
(-1)+1
假设整形以原码的形式来存储,我们来看一下计算的结果
1:00000000 00000000 00000000 00000001
-1: 10000000 00000000 00000000 00000001
求和
10000000 00000000 00000000 00000010
结果为-2,显然这个答案是错误的
再来看一下补码
1:00000000 00000000 00000000 00000001
-1: 11111111 11111111 11111111 11111111
求和
1 00000000 00000000 00000000 00000000
取前32bit位,结果为0
而且CPU中只有加法器,原码和补码之间相互转换运算过程是相同的,这样就不需要额外的硬件电路
1.2大小端
现在有一个变量a,占4个字节大小
int a=1;
那么这4个字节在内存中存储的顺序是怎么样的?
图中所示的三种存储顺序,实际情况是哪一种?
这便涉及到大小端的问题了,首先介绍下什么是大小端
大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
小端(存储)模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中
简单来说图中1就是大端存储,2是小端存储,图中3所表示的存储方式一般不会采用
2.浮点数
在介绍浮点数前先挖个坑,下面代码的结果是什么
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%dn",n);
printf("*pFloat的值为:%fn",*pFloat);
*pFloat = 9.0;
printf("num的值为:%dn",n);
printf("*pFloat的值为:%fn",*pFloat);
return 0;
}
如果说你的答案是9 9.000000 9 9.000000的话,那只能算半对
出现这样的结果和浮点数在内存中的存储有关
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
s表示符号位,s=0为负数,s=1为正数
M为有效数字1<=M<2
E是指数位
以5.5为例来说明一下
首先还是写出小数点前后的二进制位:101.1(小数点后第一位是2^-1,后面以此类推)
小数点左移,5.5就可以写成(-1)^0*1.011*2^2
存储浮点数时只需存储S、M和E即可
S在内存中占1bit大小,float类型中E占8bit,M占23bit
double类型中E占11bit,M占52bit
2.1S、M、E的存储细节
- 因为1<=M<2,所以小数点之前的值恒为1,故在存储时省略,这样可以多一位有效数字
- E的值是无符号的整数,而类似0.5这种的小数E是要小于0的,所以为解决这个问题,在存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数 是127;对于11位的E,这个中间 数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,那么存入的二进制就是10001001
由于E的存储的特殊,在取出时又分三种情况
- E的二进制全为0
那么E的真实值为-127或-1023,2^(-127)是一个很小的数,所以程序默认为0
- E的二进制全为1
E的真实值为127或1023,2^127是一个很大的数,所以默认为无穷大
- E的二进制不全为0
E-127或1023得真实值
现在来把之前的坑填上
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%dn",n);
printf("*pFloat的值为:%fn",*pFloat);
*pFloat = 9.0;
printf("num的值为:%dn",n);
printf("*pFloat的值为:%fn",*pFloat);
return 0;
}
整数9的二进制位如下:
00000000 00000000 00000000 00001001
第一个以%d形式打印,结果为9
第二个以%f形式打印,S、M、E存储的二进制如下:
E的二进制全为0,程序默认为0,所以打印0.000000
浮点数9.0二进制如下:
1001.0
转换后:(-1)^0*1.001*2^3
S、M、E中存储的二进制如下:
以%d的形式打印:二进制01000001000100000000000000000000打印出来将会是一个很大的数字
以%f形式打印:9.000000
所以打印的4个值分别为
9
0.000000
1091567616
9.000000
完



