在二进制补码系统中,同一个负数在不同大小的表示法中的表示是不同的。你不能在一个包含16位数的表达式中随意地使用8位有符号数,转换是必需的。这种转换,以及其逆操作(将16位数转换为8位)就是符号扩展(sign extension)与缩减(contraction)操作。
以数-64为例,其8位的二进制补码表示是$C0,而等效的16位二进制补码表示则是$FFC0。很显然,其位模式不一样。再看看数+64,其8位和16位表示分别是$40与$0040。一个很显然的事实就是,扩展负数的大小与扩展非负数的大小是完全不同的。
在处理无符号二进制数的时候,可以使用零扩展(zero extension)来将小位数的无符号数扩展到大位数的无符号数。零扩展非常简单——只需要用零来填充大位数操作数的高端各个字节即可。例如,为了将8位数$82零扩展到16位,只需要在高端字节中插入零,即得到$0082。
关于符号扩展和零扩展,有一点需要明确的是,它们是需要付出代价的。将一个小整型赋值给一个大整型可能会比在同样大小的整型变量间传输数据需要更多的机器指令(执行时间更长)。因此,在一个数学表达式或者一条赋值语句中混合使用不同大小的变量要小心。
以下是C语言中符号缩减的典型代码:
signed char sbyte; // C语言中的字符类型是一个字节
short int sword; // C语言中的短整型一般是16位
long int sdword; // C语言中的长整型一般是32位
. . .
sbyte = (signed char) sword;
sbyte = (signed char) sdword;
sword = (short int) sdword;
在大值超出了小值表示范围的情况下,在转换过程中会有一定的精度损失。虽然剪裁数值永远不会是一个理想的方案,但有时候这还是比产生异常或者终止计算要好。对于有些应用,例如音频与视频应用,剪裁过的结果对于最终用户来说还是可分辨的,在这种情况下,饱和操作是一种合理的转换方法。