C语言允许类型之间进行转换,包括隐式的转换和强制转换,为了我们能更好的理解这些特性,我们需要了解C语言的数据在计算机中到底是如何存储的。

整型数据

我们先从简单的整型数据开始。

无符号整数的储存比较简单,直接以二进制形式储存,64位机的signed int存储形式如下

image.png

而有符号整数的表示稍复杂,有符号整数的最高位是符号位,0代表整数,1代表负数。

image.png

在计算机中,有符号整数以补码的形式储存。关于补码,我们只需要理解它的设计的目的是为了简化有符号整数的计算,通过自然溢出实现正确的运算的结果。

可以简单的记忆如下:

(x)补码+(x)补码=0(x)补码+(x)补码=2w(w是存储的位数)x的补码可以用2wx计算得出(x)补码=2w(x)补码(x)_{补码}+(-x)_{补码}=0 \\ (x)_{补码}+(-x)_{补码}=2^w(w是存储的位数) \\ -x的补码可以用2^w-x计算得出 \\ (-x)_{补码}=2^w-(x)_{补码}

浮点型数据

浮点型数据采用下面这种方式存储,首先是32位的float

image.png

下面是64位的double

image.png

浮点数的符号位和整型类似,但浮点数只是纯粹的为了表示符号,0表示正数,1表示负数。

浮点数的指数和尾数有些细节,我们以float为例,double类似。

首先,指数位中的2进制数不能够直接转换为真实的指数,因为指数实际上有整数和负数,指数位为了能够表示正数和负数,会有一个偏移量,这个偏移量是指数位的中间值,对于float来说是127double是1023

也就是说,当指数为2时,那么指数位中存下的真实数据是129

其次,float的尾数虽然只有23位,但是float的有效位数是24位,因为在尾数部分之前,有一个固定的隐含位,这个隐含位的值是1。其实就是为尾数加上了一个固定的1作为开头。

这很好理解,因为一个非0的二进制数,至少有一个1(换做平时这可能是废话),比如6是0110,5是0101,这些数字的第一个1我们不需要储存,6就存10,5存01就可以了(当然前面还有若干个0填充),这样可以提高浮点的有效尾数。

那么浮点数怎么存0呢,当浮点数为0时,浮点数的指数位和尾数部分全部都为0,虽然这个时候尾数看起来很大,但是指数位全为0那就是-127次方,这足够逼近一个0了。

好了,其它类型的存储也无非整型和浮点型,所以不多赘述,希望本文能够让你有所收获。