整數(shù)溢出
c語言中存在兩類整數(shù)算術(shù)運算,有符號運算和無符號運算。在無符號運算里,沒有了符號位,所以是沒有溢出的概念的。
所有的無符號運算都是以2的n次方為模。如果算術(shù)運算符的一個操作數(shù)是有符號書,另一個是無符號數(shù),那么有符號數(shù)
會被轉(zhuǎn)換為無符號數(shù)(表示范圍小的總是被轉(zhuǎn)換為表示范圍大的),那么溢出也不會發(fā)生。但是,當(dāng)兩個操作數(shù)都是有符號數(shù)
時,溢出就有可能發(fā)生。而且溢出的結(jié)果是未定義的。當(dāng)一個運算的結(jié)果發(fā)生溢出時,任何假設(shè)都是不安全的。
例如,假定a和b是兩個非負(fù)的整型變量(有符號),我們需要檢查a+b是否溢出,一種想當(dāng)然的方式是:
if (a + b < 0)
溢出;
實際上,在現(xiàn)實世界里,這并不能正常運行。當(dāng)a+b確實發(fā)生溢出時,所有關(guān)于結(jié)果如何的假設(shè)均不可靠。比如,在某些
機(jī)器的cpu,加法運算將設(shè)置一個內(nèi)部寄存器為四種狀態(tài):正,負(fù),零和溢出。在這種機(jī)器上,c編譯器完全有理由實現(xiàn)以上
的例子,使得a+b返回的不是負(fù),而是這個內(nèi)存寄存器的溢出狀態(tài)。顯然,if的判斷會失敗。
一種正確的方式是將a和b都強(qiáng)制轉(zhuǎn)換為無符號整數(shù):
if ( (unsigned)a + (unsigned)b > INT_MAX)
溢出;
這里的int_max值為有符號整型的最大值。在一般的編譯器里是一個預(yù)定義的常量。ANSI C在limits里定義了INT_MAX,值為
2的31次方-1.
不需要用到無符號算數(shù)運算的另一種可行方法是:
if (a > INT_MAX - b )
溢出;