C语言之数据的存储

目录

1.数据类型的详细介绍

2. 整形在内存中的存储

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


1.数据类型的详细介绍

char         // 字符数据类型
short       // 短整型
int         // 整形
long         // 长整型
long long   // 更长的整形
float       // 单精度浮点数
double       // 双精度浮点数
它们所占空间的大小为  (1字节为8比特位)
char          1字节
short         2字节
int             4字节
long          4/8字节
long long   8字节
float          4字节
double      8字节
注意:C语言中没有字符串类型。
1.1 类型的基本归类:
整形家族:
char                                     //平常我们写的char ch;char是有符号还有无符号取决于编译器
unsigned char
signed char
short                                    //short等价于singed short
unsigned short [ int ]
signed short [ int ]
int                                          //int等价于singed int
unsigned int
signed int
long                                     //long等价于singed long
unsigned long [ int ]
signed long [ int ]
singed就是有符号其实就是有正负号的数比如温度,unsinged就是无符号其实就是只有正数的数比如年龄。
对于 singed (有符号的数据其二进制的最高位表示的是它的符号位 1 表示 负号 0 表示 正号 )
而对于 unsinged (无符号的数据其二进制的最高位也是数据位)。
浮点数家族:
float 
double

构造类型:

> 数组类型    
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union
对于数组类型它的类型其实就是去掉数组名剩下的部分例如 int arr[5] ,类型为int [5]。
指针类型:
                                //指针变量是用来存放地址的!
int * pi ;             
char * pc ;
float* pf ;
void* pv ;

 空类型:

void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。

2. 整形在内存中的存储

我们知道一个变量的创建是需要在内存中开辟空间的如int a=20我们知道a在内存中申请了四个字节的大小,那就让我们来谈谈数据是怎么在开辟的内存中存储的,首先要了解以下概念。

2.1 原码、反码、补码
计算机中的整数有三种表示方法,即原码、反码和补码。
负整数的三种表示方法各不相同。
原码
直接将二进制按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码
反码 +1 就得到补码。
正数的原、反、补码都相同。
对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统
一处理;
同时,加法和减法也可以统一处理( CPU 只有加法器 )此外,补码与原码相互转换,其运算过程
是相同的,不需要额外的硬件电路。
我们可以来验证一下整形数据在内存中是存放补码。
#include
int main()
{
	int a = 1;
	int b = -1;

	//用原码计算
	//00000000000000000000000000000001  1的原码
	//10000000000000000000000000000001  -1的原码
	//10000000000000000000000000000010  1+(-1)=-2 错误
	//用补码计算
	//00000000000000000000000000000001   1的补码
	//11111111111111111111111111111110   -1的反码
	//11111111111111111111111111111111   -1的补码

	//00000000000000000000000000000001
	//11111111111111111111111111111111   相加
	//100000000000000000000000000000000  有33位又因为最高位若为1则存不下所以舍去1
	//00000000000000000000000000000000   1+(-1)=0 正确
	printf("%d\n", a - b);
	//因为cpu只有加法器故当成a+(-b)
	return 0;
}

在内存中的存储如图

C语言之数据的存储_第1张图片

 我们知道20的二进制为0000 0000 0000 0000 0000 0000 0001 0100四个比特位化成一个字节对应为00 00 00 14 。                                                                                                                           可是和图中的顺序似乎不太对这是为什么?

2.2 大小端介绍
什么大端小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址
中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位 , ,保存在内存的高地
址中。
为什么有大端和小端:
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元
都对应着一个字节,一个字节为 8
但是在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. 浮点型在内存中的存储

常见的浮点数:
3.14159
1E10
浮点数家族包括: float double long double 类型。
浮点数表示的范围: float.h 中定义
3.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; }

他的输出结果是什么呢?

C语言之数据的存储_第2张图片由整形存进去浮点型拿出结果不一样这说明它们存储的方式是不同的

这是为什么呢?

3.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
C语言之数据的存储_第3张图片

对于 64 位的浮点数,最高的 1 位是符号位S,接着的 11 位是指数 E ,剩下的 52 位为有效数字 M
C语言之数据的存储_第4张图片
IEEE 754 对有效数字 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。比如, 2^10 E 10 ,所以保存成 32 位浮点数时,必须保存成 10+127=137 ,即 10001001。
然后,指数 E 从内存中取出还可以再分成三种情况:
E 不全为 0 或不全为 1
这时,浮点数就采用下面的规则表示,即指数 E 的计算值减去 127 (或 1023 ),得到真实值,再将有效数字M 前加上第一位的 1
比如:
0.5 1/2 )的二进制形式为 0.1 ,由于规定正数部分必须为 1 ,即将小数点右移 1 位,则为
1.0*2^(-1) ,其阶码为 -1+127=126 ,表示为
01111110 ,而尾数 1.0 去掉整数部分为 0 ,补齐 0 23 00000000000000000000000 ,则其二进制表示形式为:
E 全为 0
这时,浮点数的指数 E 等于 1-127 (或者 1-1023 )即为真实值,
有效数字 M 不再加上第一位的 1 ,而是还原为 0.xxxxxx 的小数。这样做是为了表示 ±0 ,以及接近于 0的很小的数字
E 全为 1
这时,如果有效数字 M 全为 0 ,表示 ± 无穷大(正负取决于符号位 s );
好了,关于浮点数的表示规则,就说到这里。
解释前面的题目:
下面,让我们回到一开始的问题:为什么 0x00000009 还原成浮点数,就成了 0.000000
首先,将 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
那么,第一位的符号位 s=0 ,有效数字 M 等于 001 后面再加 20 0 ,凑满 23 位,指数 E 等于 3+127=130
10000010
所以,写成二进制形式,应该是 s+E+M ,即
这个 32 位的二进制数,还原成十进制,正是 1091567616

这就是数据的存储的大致内容,了解完之后我也是醍醐灌顶

希望如果对你有帮助的话麻烦点个赞

谢谢

你可能感兴趣的:(c语言,开发语言)