有符号整数溢出

根据 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