在深度剖析之前,先大致介绍一下各数据类型:
首先数据类型的意义是使用这个类型去开辟内存空间的大小
而类型的基本归类分别是
整形家族 :
char short int long long long
tip:(将char分为整形的理由是因其存的ASCII码值的本质为整数,故将其分类为整形家族)
浮点型家族:
double float
构造类型(自定义类型) :
数组类型 结构体类型 枚举类型 联合类型
指针类型:
int* char* float* void*
空类型(通常应用于函数的返回类型、函数的参数、指针类型) :
如 void test() void test(void) void* p
接下来要介绍的才是正戏:
数据在内存中的存储 :
1. 整形在内存中的存储
2. 浮点型在内存中的存储
在这里我们先说整形在内存中的存储
1.整形在内存中的存储
首先我们知道,整形在内存中存放的其实是补码
(简单介绍一下原码、反码和补码)
int a = -10;
//10000000000000000000000000001010--原码
//11111111111111111111111111110101--反码
//11111111111111111111111111110110--补码
//想求一原码的补码只需对原码:按位取反再+1即可
int a = 10;
//00000000000000000000000000001010--原码=反码=补码(正数的3码相同)
接下来引入一个重要概念:
大端字节序存储和小端字节序存储
(一般称为:大端小端)
所谓的大端就是指将数据的高位字节保存在内存的低地址中,而将数据的低位字节保存在内存的高地址中(小端的话则相反,高存高,低存低)
单说文字可能有些抽象,这里我直接上代码大家就能明白怎么个事了:
代码如下:
int main()
{
int a = 0x11223344;
return 0;
}
这时候我们在打开内存查看a的地址(&a),能看到:
我们会发现数据并不是11 22 33 44这样子存储,相反的,是反过来存储
我们再来看看地址的高低变化:
不难看出,地址是从低到高的顺序安排的
而我们通过观察能得出,a数据里面的44属于数据的低位字节,它存放在地址中的低地址
而 11属于数据的高位字节,它存放在地址中的高地址
因此我们可以知道该编译器的存储方式是小端存储(该版是VS2019)
通过清晰的代码调试分析,我们就可以较为轻松的搞明白整形在内存中的存储,如果想知道自己的编译器是哪种存储方式,这里也有一道简单的代码可以用来自测,如下:
//判断当前编译器是大端还是小端
int main()
{
int a = 0x11223344;
char* p = (char*)&a;
if (*(p + 3) == 0x44)
printf("为大端\n");
else if (*(p + 3) == 0x11)
printf("为小端\n");
printf("%d %x", *(p + 3),*(p+3));
return 0;
}
2.浮点型在内存中的存储
首先要知道,任何一个二进制的浮点数都可以表示为如下公式:
V=(-1)^S * M * 2^E
S:表示符号位,S=0则为正数,S=1则为负数
M:表示有效数字(1<=M<2)
E:表示指数位
举个例子吧!
V=5.5
->101.1(将5.5转化为二进制)
->1.011 * 2^2(小数点向左移动了两位,E=2)
->(-1)^0 * 1.011 * 2^2(因为是正数,所以S=0)
=>(-1)^s * M * 2^E(对应公式)
通过这个代码能够更直观的理解该条公式如何应用
现在公式讲完了,那么回到标题:浮点型是如何存在数据里的呢?
我们以单精度浮点型(float (32位))为例(其中会穿插double(64位)的介绍):
先画出float内存的大致图形:
先介绍S(符号位):
S的存放很简单,如果为正数便存0,如果为负数便存1
M:
存放M时,要将整数部分的去掉,这样子就可以多拿一个bit位来存放数值
以上面的代码为例,我们的M为1.011,那么就将整数1去掉,存入011,后面读取时再将1放回即可
tip:double(64位)中M有53个bit位
E:(最复杂的)
有三种情况,如下:
1.E不全为0或不全为1
因为E是一个无符号的数,但是存的值是有正负的,因此我们需要加上一个中间值:127
(double(64位)则需加上1023)
仍然以上面的代码为例,E=2,那么就可以算作 2+127 = 129 其对应的二进制位是10000001
2.E全为0
此时E=1-127即为真实值(需要注意M不再加上第一位,而是0.xxxxx的形式,因为此时已经无限接近于0了)
3.E全为1
这时如果M全为0,则表示±无穷大
tip:double(64位)中E有11个bit位
说了那么多,现在我们来看看float类型里的5.5时如何存储的吧:
0 10000001 01100000000000000000000
再合并一下就是:
01000000101100000000000000000000