C语言学习之数据存储

在学习学习计算机/编程语言的时候,我们会有一个绕不开的话题:数据的存储。以下小编分为两部分来介绍:整型数据存储、浮点型数据存储。

一、整型数据在内存中的存储

1.我们都知道整型数据在开辟变量空间时需要4byte,那么数据是如何在这4byte的空间中存储的?

首先,我们需要了解三个概念:原码、反码、补码。计算机中的有符号数有上述三种表示方法,这三种表示方法均由符号位和数值位两部分组成。符号位(位于二进制序列的最高位):0表示正数,1表示负数。数值位:除符号位剩下的23个bit位,不同的表示方法该位存在差异。下边结合具体的数据分析 “原反补”。

①原码:将数据的绝对值转化成二进制序列,注:若是整数,最高位则为0;若是负数,最高位则为1。

②反码:将原码的符号位不变,其它位按位取反。

③补码:将反码加1,注:符号位参与运算(通常很少影响到符号位)。

注:对于无符号数和有符号整数,其 “原反补” 相等。

对于整型数据来说:数据在内存中存储的是其补码

例:下边分别对 int a = 10; 和  int b =  -10; 这两个变量的 “原反补” 进行演示:

<1>10:原反补:0000 0000 0000 0000 0000 0000 0000 1010 

<2>-10:原码:1000 0000 0000 0000 0000 0000 0000 1010

               反码:1111 1111 1111 1111 1111 1111 1111 0101

               补码:1111 1111 1111 1111 1111 1111 1111 0110

当把数据取出显示时,就涉及到从补码---->反码---->原码的转换。对于正数和无符号数而言,直接将其转化成相应的进制即可;对于负数而言,有两种方式:一是将补码除符号位外其它位取反后加1;二是将补码减一,然后把除符号位外的其它位按位取反。

2.深入理解数据的写入和读取过程

写入:如上所述的 “原反补” 约束的是原始数据!与变量本身无关!写入包含以下过程
          ①先给变量 a/b 开辟空间
          ②要将数据转化成对应的二进制,此时转化的过程和目标变量无关!!
          ③目标数据写到对应的开辟好的空间里

读取:在读取一个变量的时候,该变量的类型决定了我们(打印出来的结果)如何看对该变量内部的二进制序列的含义!!不论你              如何看待二进制序列,二进制序列本身是不发生变化的,但是经过类型解释二进制代表的含义是会发生对应的变化的。这            也就是类型的意义。举个简单的例子:比如H2O是水分子的化学式,但是它的表现形式却有固(冰)液(水)气(蒸汽)            三态,当其所处的环境不同时,则展现出不同的状态,但其本质不会发生变化。

注:数据的截断及隐式类型转换问题

在开始学习编程的时候,可能大多数的伙伴都会经历这样的情况,比如说刚定义好并初始化的变量,打印出来的结果与初始化的值不一样,这是怎么回事呢?

	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d  b=%u  c=%d\n", a, b, c);


             

如上所示的例子,定义的变量的初始化结果都是 -1 ,打印出来的结果却大相径庭。细心的你肯定已经发现了,例子中的变量的类型和打印时的类型都有所差异,这就导致了隐式类型转换问题。

首先,我们要注意C语言的输出类型,如下表展示了各种输出类型。右图为寻常算术转换体系,如果某个操作数的类型在该列表中的排名较低,首先要转换成另一个操作数的类型后执行运算。若发生整形提升,提升时对数据的二进制序列补充符号位(正数和无符号数补充0,有符号负数补充1)。

对于char a = -1; char类型的变量占1byte(8bit),输出为%d,则需要对a的类型进行提升为int,其所占的空间大小为4byte。

a:原码:1000 0001

     反码: 1111 1110

     补码: 1111 1111

提升后的补码:1111 1111 1111 1111 1111 1111 1111 1111 

转换后的原码:1000 0000 0000 0000 0000 0000 0000 0001

最高位为符号位,因此打印出的结果为-1;

b:提升后的补码与a相同,但是其打印时的类型为无符号长整型,其原码与补码相同,因此转换后的数为2^32 - 1。

c(无符号数):补码:“ 1111 1111 ”,这里就体现了前述的“原反补” 约束的是原始数据!与变量本身无关!先将-1的补码转换出来然后写入a的变量空间。

提升后的补码: 0000 0000 0000 0000 0000 0000 1111 1111 (无符号数补充0)

因此点打印的结果是255。

二、浮点型在内存中的存储

对于浮点型而言,其存储时包含三部分:符号位S,指数位E,有效数字M。如下所示为32位、64位浮点数的存储模型。

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,即1000 1001。
 
 

指数E从内存中取出来,分为以下三种情况:

E不全为0或不全为1:这种情况下,浮点数采用下边的规则表示,及指数E的计算值减去127(或 1023),得到真实值,再将有效数字M前加上第一位的1。比如:0.5的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移一位,则为1.0*2^(-1),其阶码为-1+127=126,表示为:0111 1110,而尾数1.0去掉正数部分为0,补齐0到23位:000 0000 0000 0000 0000 0000,则其二进制形式表示为:0 0111 1110 000 0000 0000 0000 0000 0000。

E全为0:该情况下,浮点数的指数E=1-127(或1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小树。这样做是为了表示正负0,以及接近于0的很小的数字。

E全为1:此情况下,若有效数字M全为0,表示正负无穷大(正负取决于符号位S)。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值