【发布时间】:2014-05-05 19:30:50
【问题描述】:
for(end = i - 1, exp = 0, long_int = 0L; end >= start; end--, exp++)
{
multiplier = pow(base, exp);
sum = 0L;
if(*(str + end) >= '0' && *(str + end) <= '9')
sum = (*(str + end) - '0') * multiplier;
else if(*(str + end) >= 'A' && *(str + i) <= (base == BASE_MAX ? 'Z' : 'F'))
sum = (*(str + end) - 'A' + 10) * multiplier;
else if(*(str + end) >= 'a' && *(str + i) <= (base == BASE_MAX ? 'z' : 'f'))
sum = (*(str + end) - 'a' + 10) * multiplier;
if(long_int >= LLONG_MAX - sum)
break;
else
long_int += sum;
}
if(sign == POSITIVE && long_int > LONG_MAX)
{
errno = ERANGE;
return LONG_MAX;
}
else if(sign == NEGATIVE && sign * long_int < LONG_MIN)
{
errno = ERANGE;
return LONG_MIN;
}
else
return (long int) sign * long_int;
我正在编写示例 strtol 实现。该代码工作正常,但有一个特殊情况我得到错误的行为。例如,让我们取一个字符串“F0000000000000000000000000000000F”,如果我们尝试转换它,我们将在开始时有一些小数字,而在转换的后期会非常大。我使用的方法不会导致溢出,因为 long_int(这是我们添加字符串后续转换字符的最终值)是 long long int,而 sum(这是我们将添加到 long_int 的值)也是 long long int。问题是我在这两个数字相加会溢出时停止函数,但在目前的情况下,long_int 的值很小,我无法将总和添加到不会导致溢出。 long_int 不满足两个 if 语句的要求,因此执行转换,最终结果是开始转换的小值。您能给我一些解决问题的建议吗?
编辑: 为了给您更好的概述,我先发布标准 gcc 函数结果的示例,然后是我的示例
0xFF000000000000000000F0 in base 0 is 7FFFFFFF
strtol: Numerical result out of range
End pointer points to ""
0xFF000000000000000000F0 in base 0 is F0
strtol: Success
End pointer points to ""
编辑2: 变量声明
#define MAX_BASE 36
..............................................................
..............................................................
long long int long_int, sum, multiplier;
int i, exp;
//base is int constant passed to a function, sign is 1 or -1 depending on a string
【问题讨论】:
-
1) 显示代码变量声明。 2) 检查
*或+操作之前 是否存在潜在溢出,而不是之后。例如。将char转换为数字后,int limit = LONG_MAX/base; if (sum > limit || ((sum == limit) && (digit > LONG_MAX%base))) Handle_Overflow(); else sum = sum * base + digit; -
更新了变量声明。你能解释一下你的方法吗?我想我看到了类似的东西,但我不认为我真的理解它。
-
1) 添加了想法:不要在 0 到 INT_MAX 的范围内累积答案,而是使用 0 到 INT_MIN 的范围。 2)
while (isalnum(*(str + end))) { int digit = foo(*(str + end)); if (digit >= base) break; if ((y <= limit) && ((y < limit) || (digit >= -(INT_MIN % base)))) { y = INT_MIN; overflow = 1; } else { y *= base; y -= digit; } end++;循环后if (sign != '-') { if (y < -INT_MAX) { overflow = true; } if (overflow) { y = INT_MAX; } else y = -y; } if (overflow) { errno = ERANGE; }GTG - 对不起。 -
通知
y -= digit;。与其将答案累积为正数,不如将答案累积为负数。 0 到 LONG_MIN 通常是比 0 到 LONG_MAX 范围更广的数字。加1。累加结果后,为正数时处理。 -
很好,您正在制定一个很好的解决方案。顺便说一句:检查
value > (LONG_MAX - char) / base> vs. >=。