最近我正在阅读其最新版本的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-statement:
#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
它始终是一个有效的数字值,为什么作者会这样做呢?
答案 0 :(得分:3)
if (result == LONG_MAX / 10 && digval > LONG_MAX % 10)
装置
if ((result == LONG_MAX / 10) && (digval > LONG_MAX % 10))
而不是
if (result == (LONG_MAX / 10 && digval > LONG_MAX % 10))
仅凭result > LONG_MAX / 10
检查是不够的,因为例如使用LONG_MAX
值,如果result
为214748364
,那么我们还需要检查digval
,因为1
不会溢出,但是9
会。