整型数据的存储与读取

    数据在计算机中是以二进制补码的形式储存的。不同的数据类型有不同的补码形式。下面分别就数据类型和数据的存放、读取讨论。

一.数据的类型
数据类型分为原生数据类型和自定义数据类型。
(1)原生数据类型(内置类型):包括我们常用的int、char、short、long、float、double.
说明:整型家族有char、int、long、short,它们又分为有符号类型(signed)和无符号类型(unsigned).其中,char类型 的数据占1个字节,int类型的数据占4个字节,short类型的数据占2个字节,long类型的数据占8个字节。
(2)自定义数据类型:包括结构体类型(struct)、联合体类型(union)、枚举类型(enum)等。
数据类型的意义:定义一个变量,我们通常要说明它的类型。而在定义一个变量时,内存就为它开辟一个空间。那么,内存是怎么开辟空间的呢?没错,这就要发挥类型的作用了。所以,类型决定了内存开辟空间的大小,还决定了使用的空间。此外,在之后对数据的操作中,我们总要结合数据的类型而参考对数据的操作,所以,类型还决定了我们如何看待所开辟空间的视角。
注意:void(空)类型不能定义变量,因为内存为空类型所开辟的空间不确定。但是,void *可以用来定义一个指向空类型的指针。因为,所定义的是指针类型,在32位处理器上,内存为指针变量开辟4个字节大小。(即所开辟内存空间大小所确定)
二.数据的存放和读取
存放:不论是有符号数还是无符号数,它们都是以二进制补码的形式存放的。只不过它们的补码形式求法不同。对于无符号数和有符号整数来说,它们的补码就是它们的二进制序列。有符号数有符号位,符号位就是最高位。正数的符号位是0,负数是1.对于有符号负数来说,我们通常先写出它的原码(符号位是1,其它位按照它的绝对值二进制序列来写。),然后通过原码写出补码(符号位不变,其余位按位取反),最后再在末位+1得到补码。

读取:在读取数据时,我们要先看它是什么类型,然后判断类型是有符号数还是无符号数。如果是无符号数,直接读取,把二进制数转化为十进制、八进制、十六进制等。如果是有符号数,先看最高位是1还是0(是负数还是整数),如果是0,则读法与无符号数相同;如果是1,则与有符号负数存储相反,先在末位上减1,然后除符号位外,其它位按位取反。

下面请看几个例题:

1.

分析:在这里定义了三个变量a,b,c,其中a和b都是有符号char型,c是无符号char型。在这里要以十进制有符号整型输出a,以无符号整型输出b,以有符号整型输出c.其中,a,b,c都占1个字节,但输出时的整型都占4个字节,所以要进行类型提升。即添加符号位。根据上面的数据存放,我们很容易知道a,b,c在内存中的存储都是11111111.添加符号位根据数据原有的类型,无符号数添加0,有符号数添加符号位。所以在a前面要添加24个1,b前添加24个1,c前添加24个0.所以它们变为:

a:1111 1111 1111 1111 1111 1111 1111 1111

b:1111 1111 1111 1111 1111 1111 1111 1111

c:0000 0000 0000 0000 0000 0000 1111 1111

下面进行读取:

a以有符号输出,那么先看符号位,最高位是1,所以a是负数,然后以负数来读取

       a:1111 1111 1111 1111 1111 1111 1111 1111

   -1:1111 1111 1111 1111 1111 1111 1111 1110

取反:1000 0000 0000 0000 0000 0000 0000 0001   -->-1

b以无符号整型输出,所以不用看符号位,直接进行读取。

所以输出为4294967295

c以有符号十进制输出,也要看其符号位。最高位是0,所以是正数,读取时直接根据二进制序列读。


例2:

分析:有符号char型的数值取值范围是:-128~127。128表示为二进制序列是1000 0000.而在有符号char型中,-128也是这样表示的,所以在内存中,a认为这里的128就是-128,符号位是1.然后要以无符号整型输出。同样进行类型提升,a前面加24个1,变为:1111 1111 1111 1111 1111 1111 1000 0000

所以输出为十进制整数4294967168.

例3:

分析:首先定义了一个有符号字符数组a,有符号char型的取值范围是:-128~127.然后对a[i]用循环赋值。最后输出a的长度。在这里,要注意字符数组长度以'\0'为标志,其实这里的0就等价于'\0'。所以我们只要计算出当i等于何值时,a[i]=0,就可以知道数组a的长度。下面先一次计算:

i=0时,a[0]=-1;i=1时,a[1]=-2;............i=127时,a[127]=-128;

i=128时,a[i]=-1-128=-1+(-128)

    -1:1111 1111

-128:1000 0000

和 : 10111 1111

但是只能取后8位,即0111 1111=127,所以a[128]=127;

i=129时,a[129]=-1+(-129)

       -1:1111 1111

-129:1 0111 1111

和:  1 0111 1110   同理,只取后8位,即为0111 1110,所以a[129]=126.

同理:a[130]=125,a[131]=124,.........a[255]=0,所以a共有256个元素,且最后一个元素是0,所以a的长度是256-1=255.

三.浮点数的存取

浮点数分为单精度float型和双精度double型,分别占4个字节和8个字节。在这里,我们先讨论单精度float型,double型类似。

1.float型:

存:我们知道,十进制小数可以化为科学计数法,同样,二进制也可以化为科学计数法:(-1)^S*M*2^E。其中S是符号位,取值是0和1;M是有效数字,取值范围在大于等于1和小于2之间;E是指数位。所以,我们存储float型的数据,实际上就是对E、S、M的存储。对于float型,共占4个字节,有32个比特位。其中,最高位存放符号位即S,接下来的8个比特位存放指数位E,剩下的23个比特位用来存储有效数字M.由于E是无符号整型,取值在0~255之间,但其实科学计数法中的E可以是负数,所以我们在存放的时候通常要给原来数据的指数位加上127。规定:计算机内部保存M时,默认这个数字的第一位总是1,因此可以被舍去,只保存后面的小数部分。等到读取的时候再自动加上1.这样就可以节省1位有效数字,对float型来说,留给M只有23位,将第一位的1舍去后,等于可以保存24位有效数字。

取:根据存放的二进制序列,我们可以把数据表示为科学计数法的形式,然后自觉给指数位减去127,有效数字部分加上1,就能够得到原有数据的二进制序列。

2.double型: 

存:先将原有数据化为科学计数法。由于double型数据共占8个字节,64个比特位。所以,它在存储时的精度就叫float型高。其中,最高位S是符号位,值为0或1;接下来是指数位E,占有11个比特位,最后是有效数字部分,占52个比特位。E的取值范围是0~2^11-1(2047)。在存时,也要给数据原有的指数位加上中间数1023。

取:同float数据一样,在把二进制数写成科学计数形式后,自动给指数部分减去1023,有效数字部分加上1.再转化为相应的进制数。

例:

      

分析:pfloat指针是一个指向float型的指针变量,那么*pfloat的值理论上应该是9.000000,怎么会输出0.000000?

9在内存中的存储为:0000 0000 0000 0000 0000 0000 0000 1001,在读取时看作浮点数存储。根据上面的取法,这个float型的数据符号位是0,紧接着的8位0000 0000是加过中间数127之后的指数部分,后面的0000 0000 0000 0000 0001 001是除去1后的有效数字部分,所以原有数据的科学计数表示为:

(-1)^0*1.00000000000000000001001*2^(-127),约等于0,所以输出为0.000000。

后来把*pfloat的内容赋值为9.0,因为9.0=(-1)^0*1.00100000000000000000000*2^3,符号位是0,指数位是3+127=130,二进制为:1000 0010,有效数字部分表示为:0010000 0000 0000 0000 0000,所以9.0在内存中的二进制序列是0 1000 0010 0010000 0000 0000 0000 0000,然后以十进制输出即为1091567616.


猜你喜欢

转载自blog.csdn.net/smell201611010513/article/details/79850396
今日推荐