一、前言
我们都知道,在C语言中数据可以分为字符型(char)、整型(int)、浮点型(float,double)这几种基本类型,其中字符型数据在计算机中是以整型形式存储的,因此,主要讨论一下整型和字符型数据在内存中存储的形式。
运行以下程序:
#include<stdio.h>
int main()
{
int num = 4;
float* p = (float*)#
printf("%d\n", num);
printf("%f\n", *p);
*p = 9;
printf("%d\n", num);
printf("%f\n", *p);
return 0;
}
如果整型和浮点型数据在内存中存储方式相同,那么无论以什么类型打印num,结果都应该一样,但事实恰恰相反,这也说明了整型与浮点型数据在存储方式上完全不同。
二、整型数据的存储
整型数据在内存中以补码的形式存储。关于原码、反码、补码的转换,请参照:https://blog.csdn.net/weixin_61486281/article/details/126102365
C语言中char类型是1个字节,但也存在4个字节的int ,8个字节的double;16位或32位的处理器的寄存器宽度也大于1个字节。因此,在内存中存储时就存在字节存储顺序的问题,这就是大小端字节序的问题。
大端字节序:数据的低位保存在内存的高地址中,高位保存在内存的低地址中。
小端字节序:数据的低位保存在内存的低地址中,高位保存在内存的高地址中。
那么,要怎么查看机器的字节序呢?有以下方法:
#include<stdio.h>
//检验机器字节序
int Fun1()
{
int i = 1;
return (*(char*)(&i));
}
//利用共用体的特点
int Fun2()
{
union
{
int i;
int c;
}un;
un.i = 1;
return un.c;
}
int main()
{
char ret = Fun2();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
三、浮点数的存储
根据国际标准IEEE规定,浮点数在内存中以表示。
- 表示浮点数的符号位,当S=1时,浮点数是负数;当S=0时,浮点数是正数;
- M是浮点数的有效数字位,1<M<2,但计算机保存M时,默认整数位是1,只保存有效数字 位;
- E是指数。
例如,十进制数5.5,写成二进制是101.1,即.
IEEE规定:对于32位浮点数,最高位是符号位,存储S;之后的8位是指数位,存储E;剩下的23位是有效数字位,存储M。对于64位浮点数,最高位是符号位,存储S;之后的11位是指数位,存储E;剩下的52位是有效数字位,存储M。
对单精度浮点数,E只占8个比特位,取值在0~255,在实际中,E有可能是负数,因此在存储时,E要加上127,而双精度浮点数则要加上1023.
注意:
1.当E全为1时,若有效数字全为0,则该数表示正负无穷大;
2.当E全为0时,若将内存中的数还原成真实值,E的真实值是1-127(1023),同时M还原时不用加上整数部分的1,直接写成0.XXXXX,表示的是接近于0的数。
3.由于浮点数在内存中存储时,小数部分可能无法正好配齐,如十进制数3.14,因此浮点数无法直接比较大小,可以通过判断浮点数是否在某个范围内比较。
四、总结
现在我们再来看前言中的题目,
- int类型的十进制数num=4在内存中存储形式00000000 00000000 00000000 00000100
- 以float形式将num从内存中取出,由于指数部分全为0,则E=1-127=-126,有效数字部分M=0.0000000 00000000 00000100,还原出的数num约等于0;
- float类型数据*p=9,在内存中存储的是0 10000010 00100000000000000000000,以int 类型取出,从符号位可知是正数,原反补码都一样,则得到1,091,567,616。