最近我正在阅读 Glibc(2.16) 最新版本的源代码。在上时strtol
,我得到了以下代码
/* some other code ... */
while (*nptr >= '0' && *nptr <= '9') {
unsigned long int digval = *nptr - '0';
if (result > LONG_MAX / 10 ||
(sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
: (result == ((unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10))) {
errno = ERANGE;
return sign > 0 ? LONG_MAX : LONG_MIN;
}
result *= base;
result += digval;
++nptr;
}
判断ERANGE
错误的代码可能看起来很难阅读,为了更清楚,我这样重新编码
unsigned long int
is_overflow(unsigned long int result, int sign, int digval) {
if (result > LONG_MAX / 10) {
goto error;
}
if (sign > 0) {
if (result == LONG_MAX / 10 && digval > LONG_MAX % 10)
goto error:
} else {
if (result == ((unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10)
goto error;
}
error:
errno = ERANGE;
return sign > 0 ? LONG_MAX : LONG_MIN;
}
我编写了一些代码来测试 long-if 语句:
#include <stdio.h>
#define LONG_MAX 2147483647L
int main() {
int sign = 0;
int expr_val = 0;
int digval = '2';
/* without any modification */
expr_val = LONG_MAX / 10 && digval > LONG_MAX % 10;
printf("%d\n", expr_val);
expr_val = (unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10;
printf("%d\n", expr_val);
return 0;
}
这些 glibc 源代码好像判断是否result
等于true
,因为expr_val
总是等于true
。
我的问题是为什么代码添加这样的测试result
,是
result > LONG_MAX / 10
足以判断连续溢出?result == 1
并且无论result == 0
它始终是有效的数字值,作者为什么要这样做?