整型与浮点型数据在内存中的存储

前言

在数据类型中,除去构造类型、指针类型和空类型,剩下的基本上都是属于整型和浮点型了,而整型和浮点型又是我们使用较为频繁的数据类型,因此,掌握整型和浮点型数据在内存中的存储方式较为重要。

1. 整型数据在内存中的存储

计算机中整型有三种二进制表示方法:原码、反码、补码。这三种表示方法都有符号位和数值位,0表示正,1表示负

1.1 原码、反码、补码

要说原码、反码、补码,还得先分两个大类,一是无符号数,二是有符号数:
对于无符号数原码、反码、补码是相同的。
对于有符号数
又分为两类,一是正数,二是负数:
正数原码、反码、补码是相同的。
负数
原码——根据一个数的二进制得到
反码——原码取反
补码——反码加上1

参考下面的图:
在这里插入图片描述
下面举个例子来具体解释以下原码、反码、补码:

#include<stdio.h>
int main()
{
    int a = 20;
    //20   
    //求原码:它的二进制序列为10100,因为是正数,符号位是0,则原码的最前面是0,其余位置补上0
    //00000000 00000000 00000000 00010100 - 原码
    //00000000 00000000 00000000 00010100 - 反码
    //00000000 00000000 00000000 00010100 - 补码
    //a在内存中存的是0x00 00 00 14
    //这是把二进制的补码转换成了十六进制
    int b = -10;
    //-10  
    //求原码:10的二进制序列为1010,而-10是负数,符号位是1,则原码最前面是1,其余位置补上0
    //10000000 00000000 00000000 00001010 - 原码
    //11111111 11111111 11111111 11110101 - 反码(原码取反)
    //11111111 11111111 11111111 11110110 - 补码(反码+1)
    //b在内存中存的是0xff ff ff f6
    return 0;
}

a和b在内存中的存储如图:
在这里插入图片描述
我们得到的 00000014 是十六进制的数,把它转换成二进制,结果为:
00000000 00000000 00000000 00010100 ---- 这就是20的补码!

由此我们可以发现,在计算机系统中,数值一律用补码来表示和存储。
原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的(都是取反后+1),不需要额外的硬件电路。
在这里插入图片描述

关于原到补、补到原都是取反+1,可以参考下面分析:

比如-1    
原码 10000000 00000000 00000000 00000001 - 原码
取反 11111111 11111111 11111111 11111110 - 反码
加一 11111111 11111111 11111111 11111111 - 补码

补码 11111111 11111111 11111111 11111111 - 补码
取反 10000000 00000000 00000000 00000000 - 注意这不是反码!!!
加一 10000000 00000000 00000000 00000001 - 原码

2. 大、小端字节序存储

什么是大小端字节序存储?
比如数字0x11223344
在计算机存储的时候,在内存的低地址到高地址中,是先存11呢,还是先存44呢,还是乱着存呢?
其实都可以,但是我们要存储方便,取出数据也要方便、精确,所以一般不考虑乱着存,于是就有两种存放数据的顺序。

大端字节序存储:
是指数据的低位字节的内容保存在内存的高地址中,而数据的高位字节的内容,保存在内存的低地址中。
小端字节序存储:
是指数据的低位字节的内容保存在内存的低地址中,而数据的高位字节的内容,保存在内存的高地址中。

比如0x11223344,其中11是高位,44是低位
   	      -------------->
    	  低地址  	 高地址
大端        11 22 33 44
小端        44 33 22 11
注意:我们讨论的高位、低位是以字节为单位的,因为16进制两个数字为一个字节,所以我们两个两个看。

大小端在vs中的例子,还是以0x11223344为例:

在这里插入图片描述
可以看到,存在内存中的0x11223344变成了44332211,这就说明了博主的电脑中的vs是小端存储的。
大家可以用下面的代码试试自己的机器是什么样的存储方式:

#include<stdio.h>
int check_sys()
{
//小端:返回1
//大端:返回0
int a = 1;
return *(char*)&a;
}
int main()
{
    int ret = check_sys();
    if (ret == 1)
    {
        printf("小端");
    }
    else
    {
        printf("大端");
    }
    return 0;
}

3. 浮点型数据在内存中的存储

首先我们要记住一点:浮点型数据和整型数据的存储方式是完全不同的!两者不可混淆!

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
1. (-1)^S * M * 2^E
2. (-1)^S表示符号位,当S=0,为正数;当S=1,为负数。
3. M表示有效数字,1<=M<2。
4. 2^E表示指数位。

例如:
float a = 5.5;
它的二进制为:101.1 从小数点右边是2的-1次,2的-2次…
根据(-1)^S * M * 2 ^ E
a = (-1)^0 * 1.011 * 2 ^ 2
又比如 0.5 = (-1)0*1.0*2(-1)
对于浮点数,只有S,M,E不一样,所以只需存储这三个数就行

在这里插入图片描述在这里插入图片描述

对于S,无非是0或1
对于M,实际上只存小数点后面的数,因为1<=M<2 ,M=1.xxxxxx,M必然是1点几,所以这个1省略不存进去
对于E,存入时,先加上127(float)或者1023(double),再转换成二进制存入。
取出数据时,分为三种情况:
1. E全为0
这时,浮点数的指数E等于-126(或者-1022)即为真实值,
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。
这样做是为了表示±0(正负取决于符号位s),以及接近于0的很小的数字。
2. E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
3. E不全为0或不全为1(就是有0有1)
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),
得到真实值,再将有效数字M前加上第一位的1。

举例:

比如float类型的0.5:
0.5的二进制形式为0.1,即1.02(-1),即(-1)01.0*2^(-1)
S=0,M=0,E=-1+127=126
存入内存的形式为:
0 01111110 00000000000000000000000

再比如float类型的6.5:
6.5的二进制形式为110.1,即1.10122,即(-1)01.101*2^2
S=0,M=1.101,E=129
存入内存的形式为:
0 10000001 10100000000000000000000
将0 10000001 10100000000000000000000转化为16进制为40d00000,去vs中验证一下是否正确:

在这里插入图片描述

至此整型与浮点型在内存中的存储梳理完成了,学会这些或许无法帮助你很明显地提高编程能力,但是却能够有效的拓宽思路,扩大视野,相信在未来一定会有某一刻是需要这些知识的!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值