strtol在Glibc的实施中感到困惑

时间:2012-10-26 02:58:01

标签: c glibc

最近我正在阅读其最新版本的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它始终是一个有效的数字值,为什么作者会这样做呢?

1 个答案:

答案 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值,如果result214748364,那么我们还需要检查digval,因为1不会溢出,但是9会。