目录:
1.整数在内存中的存储
2.大小端字节序和字节序判断
3.浮点数在内存中的存储
一.整数在内存中的存储
我们知道,整数的2进制表示方法有三种,分别是:原码,反码,补码。
对于signed int(有符号整型),三种表示方法均有符号位和数值位两部分,最高位称为符号位,用0表示“正”,1表示“负”,其余位都是数值位。
注意:1.正整数的原,反,补码均相同
2.负整数的三种表示方式各不相同
原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码;
反码;原码符号位不变,其他位以此按位取反得到的就是反码;
补码;反码+1就是补码;
对于整型而言,其存放在内存中的实际上是补码!
这里有人会想,为什么不直接存原码呢,多一目了然?
实则原码加减法比较复杂,需要事先判断数的符号,然后决定做加法还是做减法运算,这便大大增加了机器运算负担,加法器直接对原码进行加法操作有可能出错。
eg:
#include<stdio.h>
int main()
{
int a = 1;
//原码:00000001
int b = -2;
//原码:10000010
int c = 0;
c = a + b;
//原码:10000011
// -3
printf("%d\n", c);//-1
return 0;
}
而补码的用途是让机器学会减法运算的。因为所有的处理器是电路做的,电路其实只是加法器。
在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
二.大小端字节序和字节序判断
当我们大致了解了整数在内存中的存储后,我们调试看一个细节:
int main()
{
int a = 0x11223344;
return 0;
}
当我们在调试的时候打开内存窗口,我们可以看到a在0x11223344这个数字是按照字节为单位,倒着存储的,这是为什么呢?这就不得不提出大小端的概念了。
2.1.什么是大小端?
当超过一个字节的数据在内存中存储的时候,就会存在存储顺序的问题,按照不同的存储顺序,我们将它们分为大端字节序存储和小端字节序存储,下面是具体的概念:
大端存储:指将数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。
小端存储:指将数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。
对于上述案例,44就是低字节,11就是高字节,44放在了内存的最左端,即低地址处,11放在了最右端,即高地址处,这样一来,我们不难发现vs2022中选择的是小端存储模式,当然,编译器不同,存储方式会有所差异。
2.2.为什么有大小端?
为什么会产生大小端的概念呢?
如何检测当前机器的字节序呢?
eg:
#include<stdio.h>
int check_mys()
{
int i = 1;
//0x00000001
//小端:01 00 00 00
//大端:00 00 00 01
return *((char*)&i);
//找到i的第一个字节存储的内容
}
int main()
{
int ret = check_mys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
结果是小端,调用内存窗口发现的确如此:
三.浮点数在内存中的存储
对于浮点数我们已经不陌生,常见浮点数如:3.1415926,1E5(表示10的5次方);
浮点数类型包括:float,double,long double等.
浮点数表示范围:float.h中定义。
那么,内存中是如何储存一个浮点数的呢?
引例如下:
#include<stdio.h>
int main()
{
int n = 9;
float* pf = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pf的值为:%f\n", *pf);
*pf = 9.0;
printf("n的值为:%d\n", n);
printf("*pf的值为:%f\n", *pf);
return 0;
}
结果如下:
是否超出你的预料?这样的结果便与浮点数在内存中的存储有关。
3.2.浮点数的存储
上面的代码中,n和*pf在内存中明明是同一个数,为什么最终解读出的结果差别这么大?
这便需要我们弄清内存对于浮点数的存储处理:
这是国际标准规定的,举例来说:
对于十进制5.0,写成二进制就变成了101.0,相当于1.01×2^2
同理,对于十进制-5.0,写成二进制就变成了-101.0,相当于-1.01×2^2
所以,对照上面V的格式,可以得出S=0,M=1.01,E=2;
所以,根据国际标准,对于存储一个浮点数来说,只要确定了S,M,E这三个值的具体数值,便能计算出一个浮点数,因此存储浮点数的本质就是在内存中开辟空间存储这三个值。
IEEE 754规定:对于32位的浮点数,最⾼的1位存储符号位S,接着的 8位 存储指数E,剩下的 23位 存储有效数字M对于64位的浮点数,最⾼的1位存储符号位S,接着的 11位 存储指数E,剩下的 52位 存储有效数字M
图示如下:
3.2.1.浮点数储存过程
3.2.2.浮点数取的过程
指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1:
这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效 数字M前加上第⼀位的1。 ⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其 阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位 00000000000000000000000,则其⼆进制表⽰形式为:
0 01111110 00000000000000000000000//S E M
E全为0:
0 00000000 00100000000000000000000
0 11111111 00010000000000000000000