我们要学好计算机,就必须对数据在内存中的储存有了解。
总所周知,我们数据在计算机中是以二进制的形式储存的,计算机作为由一些电子硬件构成的机器,他只能通过通电和断电来实现一些数据的储存和其他操作。我们这里就不做深入解释,这里主要阐述的是数据在内存中的存储。
一、数据类型介绍
一些基本的内置的类型
char
//
字符数据类型
short
//
短整型
int
//
整形
long
//
长整型
long long
//
更长的整形
float
//
单精度浮点数
double
//
双精度浮点数
类型的意义:
-
使用这个类型开辟内存空间的大小(大小决定了使用范围)。
-
使用不同的视角看待内存空间
一.1类型的基本归类:
整形系列:
char
unsigned char
signed char
short
unsigned short
[
int
]
signed short
[
int
]
int
unsigned int
signed int
long
unsigned long
[
int
]
signed long
[
int
]
浮点数系列
float
double
构造类型:
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union
指针类型:
int *
pi
;
char *
pc
;
float*
pf
;
void*
pv
;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
二、整形在内存中的存储
我们要知道在计算机中,一个变量的创建是要在内存中开辟空间的,而空间的大小是根据所创建变量的不同类型来决定的。
接下来我们聊聊数据数据在所开辟空间中到底是如何储存的?
比如: int a = 20; int b =-10;
我们知道,这里的a是创建的整形变量,所以会为其分配四个字节的空间。 那如何储存?
来了解下面的概念:
二.1 原码、反码、补码
计算机中的整数有三种二进制的表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,符号位都是用 0 表示 正 ,用 1 表示 负 ,而数值位正数的三码都相同。
负整数的三种表示方法各不相同。
原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码。
反码
将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码
反码
+1
就得到补码。
对于整数来说:数据在内存中其实存放的是补码。为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统
一处理;
同时,加法和减法也可以统一处理(
CPU
只有加法器
)此外,补码与原码相互转换,其运算过程
是相同的,不需要额外的硬件电路。
我们看看在内存中的存储:
我们可以看到对于
a
和
b
分别存储的是补码。但是我们发现顺序有点
不对劲
。
这是又为什么?
二.2 大小端介绍
什么是大端小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址
中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位
,
,保存在内存的高地
址中。
为什么有大端和小端:
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元
都对应着一个字节,一个字节为
8 bit
。但是在
C
语言中除了
8 bit
的
char之外,还有16 bit 的short
型,
32 bit
的
long
型(要看具体的编译器),另外,对于位数大于
8
位的处理器,例如
16
位或者
32
位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因
此就导致了大端存储模式和小端存储模式。
例如:一个
16bit
的
short
型
x
,在内存中的地址为
0x0010
,
x
的值为
0x1122
,那么
0x11
为
高字节,
0x22
为低字节。对于大端模式,就将
0x11
放在低地址中,即
0x0010
中,
0x22
放在高
地址中,即
0x0011
中。小端模式,刚好相反。我们常用的
X86
结构是小端模式,而
KEIL C51
则
为大端模式。很多的
ARM
,
DSP
都为小端模式。有些
ARM
处理器还可以由硬件来选择是大端模式
还是小端模式
所以回到上面的图中,因为我们的电脑大多都是小端法储存,所以是将补码从后面开始放到内存中,注意的是,这里小端法并不是从后往前顺序完全颠倒,是一个字节一个字节的存储。
三、浮点型在内存中的存储
常见的浮点数:
3.14159
1E10
浮点数家族包括:
float
、
double
、
long double
类型。
浮点数表示的范围:
float.h
中定义
三.1 举个栗子
浮点数存储的例子:
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;
}
输出结果:
三.2 浮点数存储规则
num
和
*pFloat
在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?
要理解这个结果,一定要搞懂浮点数在计算机内部的表示方法。
详细解读:
根据国际标准
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
。
这里只做简单介绍,更多的点还需深入了解,有错误的地方欢迎大家指正,大家一起进步。