有符號整數溢位
根據 C99 和 C11 的第 6.5 / 5 段,如果結果不是表示式型別的可表示值,則表示式的求值會產生未定義的行為。對於算術型別,這稱為溢位。無符號整數運算不會溢位,因為第 6.2.5 / 9 段適用,導致任何超出範圍的無符號結果減少到範圍內值。但是,對於有符號整數型別沒有類似的規定 ; 這些可以並且確實溢位,產生未定義的行為。例如,
#include <limits.h> /* to get INT_MAX */
int main(void) {
int i = INT_MAX + 1; /* Overflow happens here */
return 0;
}
大多數此類未定義行為的例項更難以識別或預測。原則上,溢位可以來自對有符號整數的任何加法,減法或乘法運算(取決於通常的算術轉換),其中沒有有效的界限或運算元之間的關係以防止它。例如,這個功能:
int square(int x) {
return x * x; /* overflows for some values of x */
}
是合理的,並且對於足夠小的引數值它是正確的,但是對於較大的引數值,它的行為是未定義的。你無法僅根據函式判斷呼叫它的程式是否會顯示未定義的行為。這取決於他們傳遞給它的論據。
另一方面,請考慮溢位安全有符號整數運算的這個簡單示例:
int zero(int x) {
return x - x; /* Cannot overflow */
}
減法運算子的運算元之間的關係確保減法永不溢位。或者考慮這個更實際的例子:
int sizeDelta(FILE *f1, FILE *f2) {
int count1 = 0;
int count2 = 0;
while (fgetc(f1) != EOF) count1++; /* might overflow */
while (fgetc(f2) != EOF) count2++; /* might overflow */
return count1 - count2; /* provided no UB to this point, will not overflow */
}
只要計數器不單獨溢位,最後減法的運算元都將是非負的。任何兩個這樣的值之間的所有差異都可以表示為 int
。