整数表示

来源:互联网 发布:unity3d lua教程 编辑:程序博客网 时间:2024/05/09 15:56

1.无符号数和有符号数的存储

C语言支持有符号数和无符号数,无符号数在计算机中的是原码存储,而有符号数在计算机中是补码存储。

至于具体的存储方式,我unsigned char和char类型为例子进行解释。

1.1无符号数的原码表示

首先,我们知道c语言中unsigned char类型占一个字节,一共可以表示28,即256个数字,而无符号的原码表示中,所有的位都用来表示数字,所以使用原码表示的unsigned char类型一共可以表示256个数字,如果从0算起,unsigned char类型的表示范围就是[0, 255]。所以无符号整数的底层存储方式就很简单了。以unsigned char为例就是:

0 1 2 … 128 129 … 254 255 00000000 00000001 00000010 … 01000000 01000001 … 11111110 11111111

1.2有符号数的补码表示

如上所述,char类型一共可以表示256个数字,为了同时表示正整数和负整数,就必须用一半的位表示正数,一半的位表示负数。为了达到这个效果,人们将第一个位用来表示符号,叫做符号位,如果一个有符号数的符号位为1,则表示这是一个负数,如果符号位为0,表示为负数。其余位用来表示数字。可能你能想到的最简单的实现方式就是像下面这个表展示的那样:

-127 -126 … -1 -0 +0 +1 … +127 11111111 11111110 … 10000001 10000000 00000000 00000001 … 01111111

其实,这个就是有符号数的原码表示法,但是,这样的表示方法还是有很多问题,主要问题有以下几个:

1.0的表示问题,对于上面那个表,0的表示出现的两种方式,即+0和-0,按照常理来说,+0和-0没有什么区别,它们都等于0,不应该划分为两个表示。

2.如果使用上面的表进行有符号数的表示的话,运算的时候就会出现与常理不相符合的情况,比如对于+0来说,+0-1应该等于-1,而在计算机的底层,+0的二进制编码是00000000,如果对其减一,会通过借位使结果变成11111111,而11111111使用上面的编码方式结果应该是-127,这就会造成0-1等于-127的错误结果,当然我们可以在软件层面上对于这种逻辑重新解读,以达到正确的结果,但是如果能够找到一个合适的编码方式,能够使底层的运算结果和逻辑的运算结果相符合,那肯定是再好不过的。

为此,人们将上面的编码方式进行了修改,找到了一个更加合理的编码方式,即补码。对比上面的编码方式,我们写出补码的编码方式:

-128 -127 … -2 -1 0 +1 … +127 10000000 10000001 … 11111110 11111111 00000000 00000001 … 01111111

这种方式不仅解决了上面所列出的两个问题,而且也有一些新的优点,这种编码的主要优点如下:
1.0的表示唯一;
2.运算更加符合逻辑,如0-1=-1,补码表示的二进制算法00000000-00000001=11111111,结果相同;
3.上溢与下溢:如果你对char类型所能表示的最大的数字再加一,就会产生上溢,例如+127+1, 使用补码运算可得01111111+00000001 = 10000000,得到的结果为-128,这样的结果也是比较有逻辑性的,可以接受。如果你对char类型所能表示的最小的数字减一,就会产生下溢,例如-128-1,使用补码运算可得10000000-00000001 = 01111111,得到的结果为+127。这里面的逻辑是:补码使得一个类型所能表示的所有数字构成了一个环,以char为例就是下面的情形,
这里写图片描述
对一个数字就一就是在这个环中顺时针移动,减一就是在环中逆时针移动。

1.2.1补码的计算

知道了原码,补码是什么,我们下来看看如何计算原码补码,计算之前我们还要知道两个相关的编码,就是反码和移码。

反码:就是原码的符号位不变,其他位按位取反,例如上面表中-1的原码是10000001,那它的反码就是11111110.

补码:就是反码加1,如-1的补码就是111111111。

移码:就是不管正负数,只将其符号位取反即可。如-1的移码是01111111,1的移码是10000001.

2.有符号数和无符号数的转换

c语言中经常要用到类型转换,类型转换会改变编译器对这段内存空间的看法,但不会改变内存空间的内容。
在进行类型转换时,我们要清楚的知道转换之后的结果是什么,否则,程序的结果很可能不会如你所愿。
对于有符号数和无符号数之间的转换,只要我们清楚这些数的底层表示,就能准确的把握转换后的结果。

值得注意的是,c语言中,当有符号数和无符号数在一起时,编译器会先把有符号数转换为无符号数,再进行运算。

有符号数和无符号数之间的转换主要分为两种情况:

1.有符号数转换为无符号数:
这种转换即是补码转换为原码。看图就行了。
这里写图片描述

3.无符号数转换为有符号数:
这里写图片描述

3.拓展一个数字的位表示

将一个较小的数据类型转换为较大的数据类型时会产生拓展,拓展时只需记住两个规则:

1.要将一个无符号数转换为一个更大的数据类型,我们只要简单的在表示的开头添加0.这种运算被称作零拓展(zero extension).
1.要将一个二进制补码数字转换为一个更大的数据类型,规则则是执行一个符号拓展(sign extension),在表示中添加最高有效位的值。

4.截断数字

讲一个较大的数据类型转换为较小的数据类型时会产生截断。

原创粉丝点击