【问题标题】:Handling string conversion overflow, special case处理字符串转换溢出,特殊情况
【发布时间】: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 &gt; limit || ((sum == limit) &amp;&amp; (digit &gt; 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 &gt;= base) break; if ((y &lt;= limit) &amp;&amp; ((y &lt; limit) || (digit &gt;= -(INT_MIN % base)))) { y = INT_MIN; overflow = 1; } else { y *= base; y -= digit; } end++; 循环后if (sign != '-') { if (y &lt; -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 &gt; (LONG_MAX - char) / base&gt; vs. &gt;=

标签: c string


【解决方案1】:

解决了我改变了一点。而不是从头到尾,我开始通过将 i 的值计算为 value = value * base + char 来累积数字,并且还更改了溢出检查以检查 value 是否 >= (LONG_MAX - char) / base (用于正数) (值在我的代码中是 int_long 并且 sum 对应于 char)。 – 用户 3119781

我将其更改为仅检查 > (LONG_MAX - char) / base,因为它在 32 位机器上导致错误。如果它等于 LONG_MAX 但我们停在那里,我们没有溢出,所以我们不应该将溢出设置为真。现在它可以在 x86 和 x64 架构上完美运行。 – 用户 3119781

【讨论】:

    猜你喜欢
    • 2011-03-20
    • 1970-01-01
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    相关资源
    最近更新 更多