2.2.5_1 零扩展、符号扩展
00:00
各位同学大家好,在这个视频中我们要探讨一个考点,零扩展和符号扩展。那什么叫扩展呢?简单来说就是把一个短数据把它扩展为一个长数据。比如说把一个八比特的带符号整数扩展为一个16比特的带符号整数,这就是所谓的扩展。把数据的长度变长有两种方法,分别就是零扩展和符号扩展。这两种方法适用的场景各不相同。
00:32
好,首先我们先来探讨一下,为什么我们需要对数据的长度进行扩展呢?我们说一个计算机,它的机器字长决定了计算机内部的通用寄存器有多少个比特,以及也决定了它内部的这个运算器可以支持多少个比特的运算。机器字长通常是固定的,不过在计算机内部主存里面可能会有各种各样长度的数据。比如int型的变量是32位,unsigned int也就是无符号的整型也是32位unsigned short和short是16位,char型变量是八位。
01:11
由于各种数据它的长度各不相同,但是这些数据的处理依然需要依赖于通用寄存器以及ALU,需要先把数据放到通用寄存器里,然后再传给ALU进行相应的运算。由于寄存器和ALU的位数是固定的,所以在这些数据存储到寄存器的时候,以及这些数据传给ALU进行运算的时候,就有可能需要把短数据扩展为长数据,所以在这种时候我们就需要对数据的长度进行扩展。比如说把16位的扩展为32位,或者把八位的扩展为32位。所以从硬件的运行原理来看,我们需要对数据进行长度扩展。
01:58
从软件的角度来看,有时候我们也需要对数据的长度进行扩展。比如我们自己在写程序的时候,可能会定义这样的两个变量,分别是int型的变量A和short型的变量B,A的长度是32位,B的长度是16位,在软件当中我们有可能把B的值赋给A也就是把一个short型的变量赋给一个int型的变量。在这种时候我们也需要对数据的长度进行扩展。
02:28
好,接下来我们介绍两种,把数据的长度扩展的方法,分别是零扩展和符号扩展。接下来我们会尝试着把8比特的短数据扩展为16比特的长数据,我们需要关注的就是多出来的那八个比特应该用0来填补,还是应该用1来填补。
02:48
好,首先我们看无符号整数的例子,也就是C语言当中用unsigned这个关键字去修饰的那些整数。好,假设有这样的两个无符号数,分别用8比特表示。上面这个无符号数大家可以自己算一下,对应十进制90。下边这个无符号数对应十进制166,我们要把8比特扩展为16比特很简单对吧?
03:13
对于无符号数来说,每一个比特都是数值位,所以我们多出来的高位这八个比特我们全部补0就可以。高位补零并不会影响这个数的增值。以前是90,那补零之后还是90。以前是166,那补零之后增值依然是166。好,由于拓展的这些位我们是用二进制零去填充的,所以这种扩展方式就叫零扩展。零扩展适用于无符号整数。
03:45
好,接下来再看带符号的整数。我们知道计算机内部带符号整数都是用补码来表示的,上面这个数对应真值90,下面这个数对应真值负的90。好,首先来看上面这个正的90,要把它拓展为16比特。由于正数的原码和补码是一样的,所以我们只需要把这个正数的符号位保持不变,数值为1011010也保持不变,然后在符号位和数值位中间填八个零就行。这样我们就完成了从8比特的正数拓展为16比特的正数这样的一个操作,符号位和数值位中间添了八个0。
04:32
好,再来看这个负数怎么拓展。我们试着用相同的方法把符号位1保留下来,然后把数值位0100110写上去,同时符号位和数值位中间我们尝试着用八个零去填补,再来看一下拓展之后的这个补码,它的真值是否发生了改变。好,由于这是一个负数,所以我们要确它的真值就需要把补码转变成原码。
05:04
负数的补码转变成原码的方法很简单,符号位保持不变,数值位从右到左找到第一个1,这个一的右边这些部分原码和补码是一致的,而这条分界线左边的这些部分原码和补码应该刚好是相反的。所以把一变零零变一,这样我们就得到了刚才这个补码所对应的源码,显然这个源码的值肯定不是-90,所以这就意味着刚才我们把八比特补码变成16比特补码的时候,中间添零的这种方案是错误的,那正确的方法应该是符号位和数值位保持不变,中间多出来的这八个比特全部添1。大家可以自己验证一下,把这个补码转变成与之等价的原码,这个源码的值对应的增值也是-90。这就说明刚才我们拓展了这八个比特之后,这个补码的增值没有发生改变。
06:08
由于刚才我们拓展这个补码的位数的时候,多出来的这些位都是和符号位保持一致的,所以这种拓展的方法称为符号拓展。以后只要是无符号整数的位数扩展,都要用零扩展的方法,高位填零就行。而带符号整数补码的这个位数扩展,我们就需要使用符号扩展的方法,多出来的这些位和符号位保持一致。好,这就是零扩展和符号扩展,分别适用于无符号整数和带符号整数,以上就是这个视频的全部内容。