深度剖析数据在内存中的存储

目录

一、类型的基本归类

1.1整型家族

1.2浮点数家族 

二、整型在内存中的存储 

2.1大小端介绍

三、浮点型在内存中的存储

3.1在内存中存

3.2从内存中取出


一、类型的基本归类

1.1整型家族

char 

        unsigned char

        signed char

short

        unsigned short

        signed short

int

        unsigned int

        signed int

long

        unsigned long

        signed long

因为字符在内存中存储的是ASCII码值,ASCII码值是整型 ,所以字符归类到整型家族。

1.2浮点数家族 

float

double

二、整型在内存中的存储 

对于整型来说:数据在内存中是以补码形式存储 

我们看看在内存中的存储: 

 

我们能够直观的发现a在内存中存储时顺序和我们想的不一样,那a在内存中是如何存储的呢?

首先来了解一下大小端字节存储。

2.1大小端介绍

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short 型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因 此就导致了大端存储模式和小端存储模式。 

记住口诀:大端存储:高(数据高位)低(存放在低地址处)、低(数据低位)高(存放在高地址处) ,小端存储:高(数据高位)高(高地址处)、低(数据低位)低(低地址处)

举例一道面试题:

 请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

#include<stdio.h>
int main()
{
	int a = 1;
	char* p = (char*)&a;
	
	if (*p == 1)
		printf("小端存储\n");
	else
		printf("大端存储\n");
	return 0;

}

从图中可以简明的看出,如果是小端存储,则会取出第一个字节,即01 

三、浮点型在内存中的存储

3.1在内存中存

根据国际标准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规定:

对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数M。

在存储时对有效数字M和指数E,还有一些特别规定:

 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。

比如保存1.01的时 候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位 浮点数为例,留给M只有23位, 将第一位的1舍去以后,等于可以保存24位有效数字。

至于指数E,情况就比较复杂。

首先,E为一个无符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出 现负数的,所以IEEE 754规定,

存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数 是127;对于11位的E,这个中间 数是1023。

比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为 1.0*2^(-1),其阶码为-1+127=126,表示为 01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进 制表示形式为:

0   01111110 00000000000000000000000

总结来说:M存小数点后面的数字

                E:8位时+127   11位时+1023 

3.2从内存中取出

指数E从内存中取出还可以再分成三种情况:

E不全为0或不全为1

这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将 有效数字M前加上第一位的1。

 E全为0

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于 0的很小的数字。

E全为1

这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);

举例:

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;
}

为什么 0x00000009 还原成浮点数,就成了 0.000000 ?

9-> 0000 0000 0000 0000 00000 0000 0000 1001

首先,将 0x00000009 拆分,得到第一位符号位s=0,后面8位的指数 E=00000000 , 最后23位的有效数字M=000 0000 0000 0000 0000 1001。

由于指数E全为0,所以符合上一节的第二种情况。因此,浮点数V就写成:   

V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000。

再看例题的第二部分。

请问浮点数9.0,如何用二进制表示?还原成十进制又是多少? 首先,浮点数9.0等于二进制的1001.0,即1.001×2^3

9.0 -> 1001.0 ->(-1)^0*1.001*2^3 -> s=0, M=1.001,E=3+127=130

那么,第一位的符号位s=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130, 即10000010。 所以,写成二进制形式,应该是s+E+M,即

0 10000010 001 0000 0000 0000 0000 0000

这个32位的二进制数,还原成十进制,正是 1091567616 。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值