数据在内存中的存储

数据在内存中的存储

1. 大小端字节序和字节序判断

1.1什么是大小端字节序

其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为⼤端字节序存储和⼩端字节序存储,下⾯是具体的概念:
⼤端(存储)模式:是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。
⼩端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。

假设有一个十六进制数,0x11223344,没两位十六进制是一个字节,这样看比较直观一点,在数据中的存储方式有
在这里插入图片描述
第三种方式中两种显然不合适
第一种为大端字节序存储,第二种为小段字节序存储

11为数据中的高位字节,将其优先放在内存中就是大端字节序
44为数据中的低位字节,将其优先放在内存中就是小端字节序

1.2 判断当前机器的字节序

判断字节序只需要判断最低位的那个字节中存储的数据
例如:0x11223344判断低位字节中存储的是44还是11
但是这个数不易辨认,可以用1来判断
1的十六进制为 00 00 00 01
如果是小端字节序,第一个字节中存放的是01
如果是大端字节序,第一个字节中存放的是00
代码如下:

#include <stdio.h>

int check_sys()
{
	int a = 1;
	return *(char*)&a;//取出a的地址,将其存放在char*的指针中,char*类型的指针解引用只能拿到第一个字节的内容,并返回第一个字节的内容 0/1
}
int main()
{
	int ret = check_sys(); //ret用于接收返回值
	if (ret == 1) //如果为1 则为小端
		printf("小端\n");
	else          //否则则为大端
		printf("大端\n");
	return 0;
}

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

  1. 整型的二进制表示方法有:原码 补码 反码
    三种方式均有符号位和数值位两部分,其中1位符号位31位数值位
    符号位“0”表示正数,“1”表示负数,二进制中最高位为符号位

  2. 正整数的原码补码反码相同
    负整数的原码补码反码各不相同
    原码:将数值翻译成二进制得到的就是原码
    反码:原码按位取反
    补码:反码+1,补码取反+1得到原码

详细可看进制转换,在其中详细介绍了进制转换和原码补码反码的关系

整型数据在内存中是以反码形式存放的

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

常⻅的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。
浮点数表⽰的范围: float.h 中定义
一丶
根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

V = (−1)S * M * 2E
• (−1)S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
• M 表⽰有效数字,M是⼤于等于1,⼩于2的
• 2E 表⽰指数位

上述公式什么意思呢,举个例子就明白了

十进制: 5.5
二进制: 101.1

科学计数法:1.011 * 22
S = 0 M = 1.01 E = 2
套入公式: (-1)0 * 1.011 * 2 2

十进制: -5.5
套入公式: (-1)1 * 1.011 * 2 2
S = 0 M = -1.01 E = 2

个位数权重为20 十位数为21 十分位为2-1 百分位为2-2,所以0.5的二进制位0.1

二丶
对于flaot类型来说,其中最高1位用来存放S,接着8个bit位用来存放E,接着23个
bit位用来存放M
在这里插入图片描述
对于double类型来说,其中最高1位存放S,接着11bit位存放E,接着52bit位存放M
在这里插入图片描述

3.1 浮点型数据存的过程

IEEE 754 对有效数字M和指数E,还有⼀些特别规定

对于有效数字M:
例如存放M 1.xxx时,存放M的时候,不将M中个位数的1存入,由于 1 < M < 2,
所以的浮点数都默认为1,因此可以被舍去,如果舍去一位,就可以多存储小数点之后的数值,等于保存了24位有效小数

对于指数E:
E是一个无符号整数(unsigned int)
如果E为8位,那么取值范围是 0~255,如果E为11位,那儿取值范围是0~2047

但是如果存放的是十进制的 0.5,二进制为0.1,(-1)0 * 1.0 * 2-1其中 S 为 0 M 为 1.0 E为-1
E有可能是负数,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001

3.2 浮点型数据取的过程

E分为以下三种情况取出来:

  1. E不全为0或不全为1
    这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第⼀位的1
    例如 0.5的二进制位0.1
    其中S = 0 M = 1.0 E = -1 E为负数要加上一个中间值127,E为126

0 01111110 00000000000000000000000

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

0 00000000 00100000000000000000000

此时E+127(中间值) = 0,E=-127
S = 0 M = 1.xxxxx E =-127
(-1)0 * M * 2-127 这是一个接近于0的数字了

  1. E为全1 //只做了解
    这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)

0 11111111 00010000000000000000000

其中为E+127(中间值) = 255 E = 128
(-1)0 * M * 2128 这是一个很大很大的数字

3.3 代码

#include <stdio.h>
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;
}

代码运行结果如下:
在这里插入图片描述

  1. 其中n为9,以%d十进制有符号形式打印,第一个打印为9

  2. 用浮点型指针的方式拿到n里边的值
    9的二进制为

00000000 00000000 00000000 00001001

以浮点型二进制来看就是

0 00000000 00000000000000000001001
其中S = 0 M = 00000000000000000001001 E = 00000000

E为特殊情况 E全为0,所以有效数字不加上1
V=(-1)0 × 0.00000000000000000001001×2(-126)=1.001×2(-146)

V是一个接近0的数,由于%f只打印6位有效数字,所以打印出来的值位0

  1. *Float = 9.0 通过浮点型指针修改了值,内存存储方式就变了
    浮点数9.0的二进制为1001.0
    其中 S = 0, M = 1.001 E = 3 + 127(中间值) = 130

0 10000011 00100000000000000000000

转为整型的二进制就是01000001 10010000 00000000 00000000
这个值用%d十进制有符号打印就是1091567616

  1. %f打印单精度浮点型数据,打印6为有效小数,*Float为9.0,所以第四次的打印为9.000000
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

4U247

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值