数据的存储


  在前面我们提到了C语言中的内存函数(memcpy memmove memset memcmp),那么本章就来对数据在内存中的存储情况进行探讨。

1. 整数在内存中的存储

  我们知道,整数二进制的有 原码、反码、补码 三种,而整数在内存中就是以补码的形式进行存储。

2. 大小端

  大小端是一种电脑的存储模式。简单来说就是字节在内存中存储的顺序。以下是大小端具体的概念:
  大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,存储模式类似把数据当作字符串顺序处理。
  小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,存储模式将地址的高低和数据位权有效地结合起来。

2.1 为什么要区分大小端?

  在计算机系统中,都是以字节为单位,每个地址单元对应着一个字节,对于位数大于8位的处理器,由于寄存器的宽度大于一个字节,那么对字节的安排问题就出来了。

2.2 示例

  大端:将一个数值的低位字节序内容存储到高地址处,高位字节序内容存储到低地址处。
  小端:将一个数值的低位字节序内容存储到低地址处,高位字节序内容存储到高地址处。(以下皆为小端示例)
小端
其中的 0x11223344 ,11是高位,44是低位,再看到 a 地址中存放顺序,44是低位,11是高位。

图解:
大小端图解

2.3 系统大小端的判断

  想要快速判断大小端,可以通过代码实现。

#include<stdio.h>
int main()
{
	int a = 1;
	char x = *(char*)&a;   //int*转换成char*,再解引用

	if (x == 1)  
		printf("小端");
	else
		printf("大端");
	return 0;
}

运行结果:

小端

上述代码中*(char*)&a 首先是将整型指针(&a)转换成 char* 再对char*下的&a解引用,这样做是因为一个 int 是 4 个字节,char是 1 个字节 ,int转换成char之后char会取低地址的一个字节。这样,如果char取的是01,那么就说明机器是小端,反之取出00,机器就是大端。

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

  我们首先要了解浮点数在计算机内部的表示方法:

V = (−1) S * M * 2 E

V:二进制浮点数;
S:(−1) S 表示符号位,S=0 时,V为正数;S=1 时,V为负数;
M:M表示有效数字,M的范围在 1 和 2 之间;
E:表示指数位数;

例:
浮点数

对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
在这里插入图片描述

3.1 浮点数的存取过程

3.1.1 浮点数的存过程

  1. 对于M
      由于 M 的范围是 1 到 2 ,也就是 1.xxxx(x表示小数部分),所以在保存 M 时,默认整数部分为1,只存放小数部分,等到读取的时候再把 1 补上,这样 M 就可以多存放一位(24bit 或 53bit),提升了精度。
  2. 对于E
      如果 E 为 8 位,取值范围就为 0 ~ 255;如果 E 为 11 位,取值范围就为 0~2047;这些是 E 为正数的情况,但是 E 还有可能为负数。所以IEEE 754规定,存入 E 的真实值时还需加上一个中间值,8 位的中间值为127,11位的中间值为1023。例如,28的 E 是 8 ,保存为 32 位时,就为 8+127=135,即1000 0111

3.1.2 浮点数的取过程

  1. E 不为全0或不为全1
      在存的时候加上中间值,那么取的过程就要减去中间值了,例如:

0.5 的二进制为 0.1 ,根据公式,我们可以得到 E = -1,-1+127=126,即0111 1110。M 部分将1去掉, 23个位置补 0 即可。

结果: 0 01111110 00000000000000000000000

  1. E 全为0
      这时,E等于 1-127 或者 1-1023 即为真实值,有效数字 M 不再加上第⼀位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
  2. E 全为1
      这时,最后的结果就会趋近于无穷大,符号就取决于最前面的符号位(S)。

3.2 扩展

注意仔细思考以下代码

#include<stdio.h>
int main()
{
	int n = 6;
	float* pFloat = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);

	*pFloat = 6.0;
	printf("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

结果为:

n的值为:6
*pFloat的值为:0.000000
num的值为:1086324736
*pFloat的值为:6.000000
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值