【问题标题】:sscanf trouble?sscanf 麻烦?
【发布时间】:2011-03-11 03:29:14
【问题描述】:
long ip2long( char *ip )
{
    long ip2long = 0;

    char B1[4], B2[4], B3[4], B4[4];
    int D1, D2, D3, D4 = 0;

    sscanf(ip, "%s.%s.%s.%s", B1, B2, B3, B4);

    D1 = atoi(B1);
    D2 = atoi(B2);
    D3 = atoi(B3);
    D4 = atoi(B4);

    if(D1 > 255 || D2  > 255 || D3 > 255 || D4 > 255)
        return 0;

    ip2long = D1*256*256*256+D2*256*256+D3*256+D4;

    return ip2long;
}

输入数据:127.1.1.2

为什么 D1 == 127,但 D2、D3 和 D4 == 0?

--- 更新 --- 现在代码是

unsigned long ip2long( char *ip )
{
    unsigned long ip2long = 0;
    unsigned int D1, D2, D3, D4 = 0;

    sscanf(ip, "%u.%u.%u.%u", &D1, &D2, &D3, &D4);

    if(D1 > 255 || D2  > 255 || D3 > 255 || D4 > 255)
        return 0;

    ip2long = D1*256*256*256+D2*256*256+D3*256+D4;

    return ip2long;
}

Di 没问题,但还有另一个问题:127.1.1.2 的结果是 2130772226 而不是 2130772225,195.98.157.132 的结果是 -1016947324... 为什么?

--- 更新 2 --- 没关系,有 %d 个 instread %u。

Kornel Kisielewicz 感谢您介绍 inet_addr 函数 :)

PS 对不起我的英语不好 =\

问题已结束。

【问题讨论】:

  • 重新更新:我将数字输入计算器,2130772226 看起来正确。如果不使用符号位/负值,结果将不适合 32 位长。你可以返回一个无符号长整数,一个更长的有符号值(例如long long,如果你的编译器支持它),或者接受奇怪的负值。您还有其他错误(根据我的回答)。

标签: c++ c scanf


【解决方案1】:

正如 fizzer 所说,%s 消耗了整个字符串 - 在这种情况下,危险地将其复制到 S1 的末尾。如果将 sscanf() 结果与 4 进行比较,将会有一个很大的线索!不要假设事情会奏效,尤其是在解析来自程序外部的输入时。 atoi 忽略尾随垃圾,因此即使使用将在一段时间停止的 %[^.] 字符串格式,它也会通过忽略 ,3x 来处理像 192,3.2x.3.1 这样的垃圾值。

fizzer 对("...%d...", &D1...) 的建议是一个好的开始,但您仍必须将结果与 4 进行比较,否则像“hello”这样的无效字符串只会使 D1、D2、D3 和 D4 保持不变。负值将被接受。请注意,只有 D4 设置为 0 - 其他值不受该行尾随 = 0 的影响,并且可能包含来自堆栈的旧垃圾值,这些值可能会或可能不会通过稍后对 255 的检查。

总结:

unsigned long ip2ulong(char *ip)
{
    unsigned u1, u2, u3, u4;
    return sscanf(ip, "%u.%u.%u.%u", &u1, &u2, &u3, &u4) == 4 &&
           u1 <= 255 && u2 <= 255 && u3 <= 255 && u4 <= 255
           ? u1*256*256*256 + u2*256*256 + u3*256 + u4 : 0;
} 

【讨论】:

    【解决方案2】:

    第一个 %s 消耗整个输入,然后 atoi 只转换初始数字。请改用 %d,并为相应的参数传入 &D1、&D2 等。

    然后考虑对 Di 使用无符号整数,对格式转换使用 %u,对结果使用无符号长整数。 Long 可能窄到 32 位,由此产生的符号差异可能会令人惊讶。

    【讨论】:

      【解决方案3】:

      %s 的行为是贪婪的——它尽可能多地读取。您可以改用 %d 来读取数字。

      但是,您有什么理由不使用inet_addr 函数吗?它在POSIXWindows 上可用。

      【讨论】:

      • 操作系统是Linux,我可以包含什么库?
      猜你喜欢
      • 2010-11-11
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多