关于C#:将IP地址从char *转换为uin32_t


Converting IP addresses from char * to uin32_t

我的灵感来自IP地址到整数的转换

我的代码如下:

1
2
3
4
5
    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"。对我来说是新手,所以我不知道该return语句中发生了什么。


您的sscanf失败。发生这种情况时,参数将处于不确定状态。因此,您的return语句返回垃圾。

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

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

无论如何该数组都应该是无符号的,否则以后的|将会混乱(请记住,负数设置了很多1位,以2的补码表示)。

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

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

编写该函数的一种可靠方法是避免任何不受欢迎的提升:

1
2
3
4
5
6
7
8
9
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