溢出,本是一个通用的词汇。
牛奶沸腾、水库满了、电话号码升位、...,都可以用 “溢出” 来描述。
一般来说,溢出就是:容器太小,东西太多,装不下了。
但是,在计算机专业,“溢出”,却不是通用的。
在小学,大家都学过:自然数、整数(包括正整数、零和负整数)。
存入计算机后,就被改名为:无符号数、带符号数。
不论什么数,在计算机中,都是用 “二进制机器码” 表示和存储。
其实,在计算机中,并没有任何的数字。
常说的 1 和 0 都是代码,都是指:计算机内部的高电平和低电平。
八位的二进制机器码,所代表的数字,如下图所示:
由图可见,它们代表无符号数的范围是:0 ~ 255;
代表带符号数的范围是:-128 ~ +127。
当计算机的运算结果,超出了上述的范围,必然就会溢出。
就是说:无符号数、带符号数的运算,都是有可能溢出的。
但是,在 Intel 公司:
只把 “带符号数” 的溢出,才称为 “溢出”;
而 “无符号数” 的溢出,则要称为 “进位”。
因为,Intel 在设计 CPU 时,设计了两个标志位:CF、OF。
当无符号数运算结果超出上下限时,将有:CF = 1,这就叫 “进位”。
当带符号数运算结果超出上下限时,将有:OF = 1,这才叫做 “溢出”。
搞计算机的人,真是脑回路清奇呀! 常识,都被他们弄的混乱不堪。
-----------------------------
对于无符号数来说,什么是进位,还是很容易理解的。
比如:1 + 9 = 10。
本来是一位数的运算,结果,却多出来一位,这就是进位。
如果用机器码来运算:1 + 255,结果就是 0,同时还有:进位 1。
-----------------------------
对于带符号数来说,什么是溢出,就不太容易理解了。
比如用机器码来计算:1 + 127 = 128。
这次运算结果,就超出了-128 ~ +127 的范围,应该是溢出了。
由图可见,机器码 1、127 都是正数,而 128 代表的却是负数!
正+正,结果却出现了负数! 这就是溢出的特征之一。
(注意,此次运算,并没有出现进位。)
------------------
另外,再用机器码计算:129 + 130 = (进位 1) 3。
这应该是-127 和-126 相加,和应该是-253,又超出范围了。
现在的和,却是 +3 !
负+负,结果却出现了正数! 这也是溢出的特征之一。
(进位为 1,但是它不属于八位数,所以就忽略不计了。)
结论:
正+正、负+负,结果可能会超出范围,造成溢出。
正+负、负+正,越加绝对值就越小,绝不会超出范围,肯定不会溢出。
溢出的特征是【结果的正负号,不符合正常逻辑关系】。
-----------------------------
CPU 在用机器码进行计算的时候,并不知道这些机器码所代表的,究竟是什么数字。
但是,无论它们是无符号数还是带符号数,加减运算的过程,都是相同的。
CPU 进行运算之后,它会自动给出标志位 CF 和 OF。
当 CF = 1,就说明用机器码作为无符号数来运算,出现了进位。
当 OF = 1,就说明用机器码作为带符号数来运算,出现了溢出。
注意:溢出不等于进位,进位也不等于溢出。两者互不相干。
-----------------------------
人工判断溢出,都有什么方法呢?
1. 只有 “正+正、负+负” 或 “正-负、负-正”,才有可能溢出,其它的绝不会溢出。
2. 用机器码代表的十进制数,计算一下,如果运算结果超出预定范围,就是溢出了。
3. 用机器码当做补码来运算,观察两个操作数和运算结果的符号位,不符合逻辑就是溢出。
4. 采用 “双符号位” 法进行计算,如果两个符号位不同,就是发生了溢出。
5. 采用 “双进位法” 进行判断,如果两个进位不同,就是发生了溢出。
---------------
上述的 “双符号位” 法,只适合于人工计算,目前还没有听说那个 CPU 具有 “双符号位” 。
上述的 “双进位法” ,是 CPU 通过硬件进行判断的方法。
硬件知识是很难懂的,所以,任何参考书上,都没有给出这种方法的理论依据 。
我们暂时就相信,这方法是正确的吧。
本文完。