sscanf麻烦?

时间:2011-03-11 03:29:15

标签: c++ c scanf

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;
}

迪是好的,但还有另一个麻烦:127.1.1.2的结果是2130772226而不是2130772225,结果195.98.157.132是-1016947324 ... 为什么呢?

---更新2 --- 多数民众赞成,%d instread%u。

Kornel Kisielewicz感谢您讲述inet_addr函数:)

对不起我的英语不好= \

问题已经结束。

3 个答案:

答案 0 :(得分:7)

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

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;
} 

答案 1 :(得分:5)

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

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

答案 2 :(得分:5)

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

但是,有没有理由不使用inet_addr功能?它位于POSIXWindows