C语言应该怎么玩——数据存储

一、数据类型的介绍

char         //字符数据类型
short        //短整型
int          //整型
long         //长整型
long long    //更长的整型
float        //单精度浮点数
double       //双精度浮点数

类型的意义:
1、使用这个类型开辟内存空间的大小(大小决定了使用范围);
2、如何看待内存空间的大小。
这里提一下char型,为什么char也属于整型呢?
解释:字符类型在底层存储的是这个字符的ASSCII码值,ASCII码值也是个整数,所以在归类的时候,把char归类到整型家族里去。

1、整型家族

char
      signed char
      unsigned char
short
      signed short (int)
      unsigned short (int)
int
      signed int
      unsigned int
long
      signed long (int)
      unsigned long (int)

2、浮点数家族

float
double
long double

3、构造类型(自定义类型)

//数组类型
//结构体类型 struct
//枚举类型 enum
//联合类型 union

4、指针类型

int* pi
char* pc
float* pf
void* pv

5、空类型(void)

//函数返回类型 void test()
//函数参数 void test(void)
//指针 Void* p

二、整型在内存中的存储

一个变量的存储是要在内存中开辟空间,开辟空间的大小是由变量的类型决定的,下面以整型数据的存储为例:
整型(int)的大小是4个字节,内存会为其分配4个字节的空间,那具体是怎么存储的呢?
在这里插入图片描述
在这里插入图片描述
图片中箭头指向的就是a、b在内存中的存储。可能有人会问计算机内存储的不都是二进制数嘛,为什么这里是十六进制数的形式?
解释:虽然计算机是以二进制的形式存储,但是在展示数据在内存中的存储的时候,用二进制形式展示实非明智之举,但用十六进制形式展示简洁明了,所以就是十六进制了(这么莽的解释第一次见吧,由此可见博主的水平还是很low的 。(T o T)

在展示数据的时候,比如图中的b=-10,为什么在展示b在内存中的存储的时候,展示的十六进制数是 f6 ff ff ff 呢?这需要先了解原码、反码、补码和大小端字节序的概念。

1、原码,反码,补码

在这里插入图片描述
在计算机系统中,数值一律用补码表示和存储,原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)(减法用加法来模拟处理)。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

了解补码之后,我们就可以来算刚刚展示的那个十六进制数了:
在这里插入图片描述
算完后发现结果为 ff ff ff f6 ,但是展示的结果是 f6 ff ff ff ,这又是为什么呢?这就需要了解另一个概念——大小端字节序。

2、大小端字节序

大端字节序:把数据的低位字节序的内容存放在高地址处,高位字节序的内容存放在低地址处。

小端字节序:把数据的低位字节序的内容放在低地址处,高位字节序的内容放在高地址处

在这里插入图片描述
这里提一下什么是数据的低位字节序和高位字节序:
举个例子,对于十进制数,1001(一千零一),千位1表示的数据大,它就是高位字节,个位1表示的数据小,它就是低位字节;同样,对于十六进制数,0x1122,0x11就是高位字节,0x22就是低位字节。

用图来演示大小端字节序很容易理解,接下来再用代码来演示一下:
在这里插入图片描述
通过代码演示可以看出当前的编译器(vs2022)采取的是小端存储模式。

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

这里提一下:
写一个代码判断当前机器的字节序:
在这里插入图片描述
(大家也可以用这个简单的代码来测一下自己的编译器是哪种存储模式。)

这里提一下:
char类型变量的取值范围:

在这里插入图片描述
char的取值范围还可以通过下面的图来理解:
在这里插入图片描述
上面分析的是有符号的char的取值范围:-128 ~ 127无符号的char的取值范围是:0 ~ 255。(通过上面对有符号的char的分析,无符号的char的取值范围也就很好理解了。)

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

根据国际标准IEEE(电气与电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式:

(-1)^S * M * 2^E
(-1)^S表示符号位,当S=0时,V为正数;当S=1时,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。

接下来我们用个例子来展示IEEE754具体怎么用:
在这里插入图片描述

IEEE 754规定:

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

在这里插入图片描述

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

在这里插入图片描述
IEEE 754对有效数字M和指数E还有一些特别规定。前面说过,1<=M<2,也就是说,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保留后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省一位有效数字。以32位浮点数为例,留给M的只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

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

首先,E为一个无符号整型,这意味着,如果E为8位,它的取值范围为0 ~ 255;如果E为11位,它的取值范围为0 ~ 2047。但是,科学计数法中的指数是可以出现复数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
什么意思呢?举个例子,十进制数0.5,转换成二进制是0.1,根据二进制数的规则,0.1写成科学计数法应该是1.0 * 2^(-1),对应的S=0,M=1.0,E=(-1),但是E是一个无符号整型,不可能为负数,所以按照IEEE 754的规定,存E的时候需要先加上中间数然后再存。回归我们举的例子,如果把0.5存进float型变量里面,E(此时等于-1)要先加上127,得到126,再把126(二进制形式是01111110)存进那8bit的空间;如果把0.5存进double型变量里面,E要先加上1023,得到1022(二进制形式是01111111110),再把1022存进那11bit的空间。再比如,2 ^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
刚刚介绍的是怎么把浮点数存进内存。然后指数E从内存中取出还可以再分为三种情况:E不全为0或不全为1;E全为0;E全为1。这里就不再做介绍了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值