作者:@匿名者Unit
目录
- 一.数据类型分类
- 1.整形
- 2.浮点型
- 3.构造类型
- 4.指针类型
- 5.空类型
- 二.整形的存储
- 1.原、反、补码
- 2.大小端存储
- 三.浮点数的存储
一.数据类型分类
根据不同的数据类型,在内存中的人存储方法也有所差异,所以我们先来介绍一下数据类型的分类。
1.整形
char
unsigned char
signed char
short
unsigned short [int]//int在定义时可写可不写
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
2.浮点型
float
double
long double
3.构造类型
/*数组类型*/ int arr[]
/* 结构体类型*/ struct
/* 枚举类型*/ enum
/* 联合类型*/ union
4.指针类型
int *pi;
char *pc;
float* pf;
void* pv;
5.空类型
- void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
二.整形的存储
1.原、反、补码
-
整数在内存中是以二进制的形式进行存储的,计算机有三种整数二进制的表示方法:原码、反码、补码。
-
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负。
-
正数的原反补码都相同,而负数的原反补需要计算得来。
-
原码:
直接将数值按照正负数的形式翻译成二进制就可以得到原码。 -
反码:
将原码数值位取反得到反码。 -
补码:
反码+1得到补码。
2.大小端存储
我们创建两个变量在内存中观察一下,发现a和b变量的存储顺序不太对劲。
下面我们介绍两种存储方式:
大端存储(大端字节序存储):
把一个数据的低位字节内容存放在高地址,高位字节的内容存放在低地址处。
小端存储(小端字节序存储):
把一个数据的低位字节内容存放在低地址处,高位字节内容存放在高地址处。
了解的大小端存储的区别,我们不免会思考为什么会有不同的存储方式存在呢?在我看来有以下几种原因:
- 大小端存储方式存入和取出都比较方便。
- 由于寄存器宽度大于一个字节,所以必然会面临多个字节存储顺序的问题。
- 可以根据硬件实际情况选择适合的存储方式。
三.浮点数的存储
在研究浮点数在内存中的存储之前我们先来看一段代码:
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;
}
运行结果如下:
想要解释此现象必须先了解,浮点数在内存中的存储方式:
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。 M表示有效数字,大于等于1,小于2。
2^E表示指数位。
举例来说:
十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上面V的格式,可以得出S=0,M=1.01,E=2。
十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
IEEE 754规定: 在不同的机器位数上,浮点数的存储方式也有区别。
IEEE 754对有效数字M和指数E,还有一些特别规定:
- 因为1<M<2,所以M总是1.xxxxxxxxx,在存储M的值时会省略前缀1,只存xxxxxxxx。
- E为一个无符号整数 ,但是E是会有负数的,所以规定存入E值时必须加上中间数,32位机器上是127,64位机器是1023
- E不全为0或不全为1时 :指数E的计算值减去127(或1023),得到真实值
- E全为0 ,这时,浮点数的指数E等于1-127(或者1-1023) 即为真实值,
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。- E全为1 ,这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
了解清楚浮点数的存储规则后,我们就可以解释上面的现象是由于整数和浮点数在内存的存储方式不同所造成的。
int main()
{
int n = 9;
//00000000000000000000000000001001 - 9的补码
//0 00000000 00000000000000000001001
//(-1)^0 * 0.00000000000000000001001 * 2^-126
//0.000000
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);//9
printf("*pFloat的值为:%f\n", *pFloat);//0.000000
*pFloat = 9.0;
//1001.0
//(-1)^0 * 1.001 * 2^3
//s=0
//e=3
//m=1.001
//01000001000100000000000000000000
//
printf("num的值为:%d\n", n);//1,091,567,616
printf("*pFloat的值为:%f\n", *pFloat);//9.0
return 0;
}