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