【问题标题】:Converting IP addresses from char * to uin32_t将 IP 地址从 char * 转换为 uin32_t
【发布时间】:2015-12-04 06:52:54
【问题描述】:

我的灵感来自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”。对我来说是新的,我不知道返回声明中发生了什么。

【问题讨论】:

  • 这就是为什么你检查scanf和朋友的返回值
  • "%hhu" 修饰符应该放在第一位而且应该是unsigned char ipbytes[4];
  • 请注意,这些是带符号的字符,它们被符号扩展为整数。
  • 为什么要重新实现 inet_pton() ?

标签: c


【解决方案1】:

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

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

您可能是指%hhu,读取一个整数并存储在unsigned char 中,但是您还需要将ipbytes 设为unsigned char 以匹配格式说明符。普通字符或带符号字符的说明符是%hhd

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

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

最后,如果系统有 16 位 int,那么 &lt;&lt; 16&lt;&lt; 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;
}

如果你真的想使用|&lt;&lt;,那么你要么必须使用一些丑陋的演员表;或将ip 更改为uint32_t 类型,在这种情况下"%u" 必须替换为"%" SCNu32

【讨论】:

  • 我的解决方案没有检测到输入的数字大于255 的情况(在这种情况下它会返回垃圾) - 尽管您的原始代码也没有处理得很好。要检测这种情况,您可以添加额外的 line ,例如if ( (ip[0] | ip[1] | ip[2] | ip[3]) &gt;= 0x100 ) return 0;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 2013-05-09
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多