将IP地址从char *转换为uin32_t

时间:2015-12-03 22:38:27

标签: c

我受Conversion of IP address to integer

的启发

我的代码如下所示:

    uint32_r parseIPV4string(char * ipAddress){
    char ipbytes[4];
    sscanf(ipAddress, "%uhh.%uhh.%uhh.%uhh", &ipbytes[3], &ipbytes[2], &ipbytes[1], &ipbytes[0]);
    return ipbytes[0] | ipbytes[1] << 8 | ipbytes[2] << 16 | ipbytes[3] << 24;
}

几乎是一个精确的副本,我的问题是,我的IP地址没有正确出来。我正惊恐地看着“129.173.118.0”和“129.173.31.187”都返回2164260864

有人可以解释发生了什么吗?

也许我错误地使用了解析器,我不确定它是如何工作的,即“%uhh”。对我来说是新的,我不知道返回声明中发生了什么。

1 个答案:

答案 0 :(得分:3)

您的sscanf失败了。当发生这种情况时,它会使参数处于不确定状态。所以你的return语句会返回垃圾。

%uhh表示阅读unsigned int,然后匹配字母'h'两次。如果您的输入字符串在第一个数字后实际上不包含h,则匹配失败并且sscanf将返回1(或0如果甚至没有第一个数字)。

您可能需要%hhu来读取整数并存储在unsigned char中,但您还需要使ipbytesunsigned char以匹配格式说明符。普通或签名字符的说明符是%hhd

无论如何,这个数组应该是无符号的,否则你的|稍后就会搞砸(请记住,负数在{2}补码中设置了很多1位。

另一个问题是,如果您的系统具有32位int,那么即使使用unsigned char,如果设置了ipbytes[3] << 24的高位,表达式ipbytes[3]也会导致未定义的行为,由于有符号整数溢出:整数促销不幸地将unsigned char提升为已签名的int

最后,如果系统具有16位int,那么<< 16<< 24将完全失败。

编写该功能的一种有效方法是避免任何不良促销:

uint32_t parseIPV4string(char const * ipAddress)
{
    unsigned int ip[4];

    if ( 4 != sscanf(ipAddress, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]) )
         return 0;   // or some other indicator or error

    return ipbytes[3] + ipbytes[2] * 0x100 + ipbytes[1] * 0x10000ul + ipbytes[0] * 0x1000000ul;
}

如果你真的想使用|<<那么你要么必须使用一些丑陋的演员表;或者更改ip以使uint32_t类型"%u"必须由"%" SCNu32替换。