我受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”。对我来说是新的,我不知道返回声明中发生了什么。
答案 0 :(得分:3)
您的sscanf
失败了。当发生这种情况时,它会使参数处于不确定状态。所以你的return
语句会返回垃圾。
%uhh
表示阅读unsigned int
,然后匹配字母'h'
两次。如果您的输入字符串在第一个数字后实际上不包含h
,则匹配失败并且sscanf
将返回1
(或0
如果甚至没有第一个数字)。
您可能需要%hhu
来读取整数并存储在unsigned char
中,但您还需要使ipbytes
为unsigned 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
替换。