2.3 数据的存储原理、数据范围、溢出现象

本文详细解析了数据的定点存储和浮点存储机制,包括原码、反码和补码的转换过程,以及不同类型数据如字符型和float的存储结构。同时讨论了数据范围和溢出现象,以short型-32768的补码为例说明特殊情况的处理。
摘要由CSDN通过智能技术生成

       在上一讲中我们介绍了数据的进制转换以及字面值常量的前后缀,那么,数据是怎样在内存中存储的呢?不同数据类型的存储方式是否有不同呢?每种类型的数据的数据范围是多少?

        (注:本讲内容相对复杂,建议反复阅读几遍)

一、数据的存储原理

       我们在前面介绍变量的时候,将变量按照存储方式分为了定点存储浮点存储。那么它们的存储方式有什么区别呢?

        1、定点存储

       定点存储的方式指的是将数据的二进制原码转化为反码,再将反码转化为补码,最后以补码的形式存储于内存的存储方式。

       原码:有符号类型数据的原码指的是符号位加数据的二进制真值的绝对值,用二进制的左边第一位表示符号(正数为0,负数为1),其余位为数值位,存储该数据绝对值的二进制数。例如:有符号int类型-13的原码为(由于int类型的数据占据4byte = 32bit的存储空间,所以它的二进制数值有32个二进制比特位):

       1000 0000 0000 0000 0000 0000 0000 1101

       无符号类型的原码即所有位均为数值位,没有符号位。

       反码:正数的反码即为它本身;负数的反码是其在原码的基础上,符号位不变,数值位按位取反(0变为1,1变为0),例如:有符号int类型-13的反码为:

       1111 1111 1111 1111 1111 1111 1111 0010

       补码:正数的补码即为它本身;负数的补码是将其反码的基础上+1

       将补码还原为原码的方式也与上述转化方法类似:如果补码的符号位为0,说明这是一个正数,那么补码本身就是它的原码;如果符号位为1,那么这个数是一个负数,我们需要将它的数值位按位取反,然后将取反的结果符号位不变,数值位+1,就得到了它的原码。

       这里需要注意的是,字符型数据在存储时也是用的定点存储的方式,它存储的是这个字符对应的ASCII码值,这个我们后面会单独在一讲中介绍。

        2、浮点存储

       这里我们以float类型为例,一个float类型数据在内存中占4个字节(即32bit),我们将这32个比特位从右至左依次称为第0位~第31位。我们将这32个比特位依次分为:

       符号位(第31位):这一位用来表示这个实数是正数还是负数,为0表示正数或0,为1表示负数。

       阶码(第30位~第23位):这8位用来表示该实数转化为规格化的二进制实数后的指数与127之和的二进制数,我们称之为阶码。我们将阶码填写在这8位上,位数不足的在前面用0补齐即可。

       规格化:类似于十进制中的科学计数法,我们需要将二进制形式的浮点数的小数点向前移动,直到小数点前面只有一个1,后面乘以2的移动位数次方。例如110010.0011规格化后的结果为:1.100100011×25。

       尾数(第22位~第0位):这23位用来表示规格化后的二进制实数的小数部分,不足23位在后面用0补齐。

       为什么要在指数上加127作为阶码?

       这个127称为偏移量,为了能够表示指数为负这种情况,我们将规格化后的指数加127(偏移量)作为阶码,这样我们可以表示的阶码范围就是-126~127,而不是0~255,这样可以用来表示更小的浮点数且尽量不丢失精度。

       我们以float类型的十进制数值127.25为例:

        首先,127.25的二进制为:111 1111.01;

        接着,127.5为正数,所以符号位为0;

        然后我们将它规格化,结果为:1.1111 1101×26;

        我们再将指数+127,结果用二进制表示作为阶码:1000 0101

        最后我们将规格化后的小数部分(1111 1101)作为尾数,后面用0补齐,就得到了127.25在内存中的存在形式:0 1000 0101 1111 1101 0000 0000 0000 000

 

二、不同类型数据的不同范围:

       由于每种数据类型所占用的字节数以及存储方式各不相同,所以它们可表示数据的范围也有不同。那么,每种类型的数据范围分别是多少呢?

       我们以有符号字符型数据(signed char)为例,由于char类型占用1byte(8bit),那么它共有8个比特位,其中第7位(最前面的一位)用来表示符号,那么它的数值共由7个比特位决定,这7位分别有0和1两种情况,又因为这些数据是连续的,所以当第7位是0时,它可表示是27=128个数据(0~127);同理,当第7位是1时,它可以表示128个数据(-128~-1)。我们将它们拼接在一起,就得到了有符号字符型数据的数据范围(-128~127),共256个数字。

       如果是无符号字符型数据(unsigned char),那么第7位也用来表示数值,这时的范围就是28=256个数字,即0~255。

       按照上面的道理,我们可以得出C语言常见的基本数据类型的数据范围如下:

 

三、溢出现象

       在计算机进行计算等操作时,如果得到的结果太大以至于原有的存储空间不足以存储操作结果时就会发生溢出现象。在二进制中的体现为将最前面一位舍去。例如:

       char类型十进制数-1的二进制补码表示为1111 1111,在进行+1操作时,补码进行+1操作,结果为1 0000 0000,最前面的1溢出,舍去,结果补码为0000 0000,即十进制的0。

附:为什么short型-32768的补码为1000 0000 0000 0000

       我们刚刚在计算数据类型的范围时,细心的同学就会发现:每个有符号类型的最小数据都无法用原码来表示,比如short类型的-32768,我们会发现它无法在short规定的16比特位的范围内表示出原码,所以-32768的二进制补码只能用-32767-1来推算:

        -32767-1 = -32767+(-1)

        -32767的补码为1000 0000 0000 0001

        -1的补码为1111 1111 1111 1111

        相加:

       我们可以看到,相加的结果发生了溢出现象,结果为1000 0000 0000 0000,恰好这个二进制数没有用来表示任何数的补码(准确来说是任何short类型数值的补码都不可能是它),所以我们认为规定short类型的-32768的二进制补码为1000 0000 0000 0000。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值