4.1.2 算术结果溢出

我们在前面已经接触过算术结果溢出的相关知识,例如,占据4字节32位内存空间的数据经过运算后,得到的结果超出了存储空间的大小,这时就会产生溢出现象。

又如,int类型的数据0xFFFFFFFF加2得到的结果将会超出int类型的存储范围,超出的部分也称为溢出数据。溢出数据无法被保存,将会丢失。对于有符号数而言,原数据为一个负数,溢出后由于表示符号的最高位被进位,原来的1变成了0,这时负数也相应地成为了正数,如图4-4所示。

图 4-4 溢出结果对比

图4-4中演示了数据是如何产生溢出的,以及溢出后为什么数据会改变符号(由一个负数变为正数)。一个无符号数产生溢出后会从一个最大数变为最小数。有符号数溢出会修改符号位。具体的示例如代码清单4-10所示。

代码清单4-10 利用溢出跳出循环


//看似死循环的for语句

for(int i=1;i>0;i++)

{

printf("%d\r\n",i);

}


代码清单4-10中的for循环看上去是一个死循环,但由于i是一个有符号数,当i等于它允许取得的最大正数值0x7FFFFFFF时,再次加1后,数值会产生进位,将符号位0修改为1,最终结果为0x80000000,这时的最高位为1,按照有符号数进行解释,这便是一个负数,对于for循环而言,当循环条件为假时,则会跳出循环体,结束循环。

溢出是由于数据进位后超出数据的保存范围导致的。溢出和进位都表示数据超出了存储范围,它们之间又有什么区别呢?

进位

无符号数超出存储范围叫做进位。因为没有符号位,不会破坏数据,而多出的1位数据会被进位标志位CF保存,数据产生了进位,只是进位后的1位数据1不在自身的存储空间中,而在标志位CF中。可通过查看进位标志位CF,检查数据是否进位。

溢出

有符号数超出存储范围叫做溢出,由于数据进位,从而破坏了有符号数的最高位—符号位。只有有符号数才有符号位,所以溢出只针对有符号数。可查看溢出标志位OF,检查数据是否溢出。OF的判定规则很简单,如果参与加法计算的数值符号一致,而计算结果符号不同,则判定OF成立,其他都不成立。

也有其他操作指令会导致溢出或进位,具体请参考Intel手册。