使用htonl(inet_addr(IP_str))将点分IP转换为整数返回B类和C类IP地址的负值

时间:2017-02-22 14:06:35

标签: c linux htonl

我正在尝试使用htonl(inet_addr(IP_str))将点分IP转换为整数。

问题是该函数返回B类和C类IP地址的负面结果。

这是我的一些代码(简化):

int main() {
const char IP1[] = "10.0.0.0";  //Class A
const char IP2[] = "20.0.0.0";  //Class A    
const char IP3[] = "126.0.0.0";  //Class A
const char IP4[] = "128.0.0.0";  //Class B
const char IP5[] = "160.0.0.0";  //Class B
const char IP6[] = "190.0.0.0";  //Class B
const char IP7[] = "193.0.0.0";  //Class C
const char IP8[] = "200.0.0.0";  //Class C

uint32_t integer_ip;
integer_ip = htonl(inet_addr(IP1));
printf("IP1: %s ------> Integer: %d\n",IP1,integer_ip);
integer_ip = htonl(inet_addr(IP2));
printf("IP2: %s ------> Integer: %d\n",IP2,integer_ip);
integer_ip = htonl(inet_addr(IP3));
printf("IP3: %s ------> Integer: %d\n",IP3,integer_ip);   
integer_ip = htonl(inet_addr(IP4));
printf("IP4: %s ------> Integer: %d\n",IP4,integer_ip);
integer_ip = htonl(inet_addr(IP5));
printf("IP5: %s ------> Integer: %d\n",IP5,integer_ip);
integer_ip = htonl(inet_addr(IP6));
printf("IP6: %s ------> Integer: %d\n",IP6,integer_ip);
integer_ip = htonl(inet_addr(IP7));
printf("IP7: %s ------> Integer: %d\n",IP7,integer_ip);
integer_ip = htonl(inet_addr(IP8));
printf("IP8: %s ------> Integer: %d\n",IP8,integer_ip);
return 0;
}

和结果:

IP1: 10.0.0.0 ------> Integer: 167772160   
IP2: 20.0.0.0 ------> Integer: 335544320
IP3: 126.0.0.0 ------> Integer: 2113929216
IP4: 128.0.0.0 ------> Integer: -2147483648
IP5: 160.0.0.0 ------> Integer: -1610612736
IP6: 190.0.0.0 ------> Integer: -1107296256
IP7: 193.0.0.0 ------> Integer: -1056964608
IP8: 200.0.0.0 ------> Integer: -939524096

我在一些在线工具上测试了结果,例如this一个。

考虑这一行输出:

IP5: 160.0.0.0 ------> Integer: -1610612736

-1610612736等于160.0.0.01610612736等于96.0.0.0.

对我来说最重要的要求是速度。 我不想检查每个IP是否属于A类。

我该如何解决这个问题?

感谢?

4 个答案:

答案 0 :(得分:4)

您的代码调用未定义的行为,以便将无符号整数打印为带符号。

要打印stdint.h类型,请参阅inttypes.h。使用PRIu32宏打印uint32_t

uint32_t u = 42;
printf("Value: %" PRIu32 "\n", u);

如果%u不是uint32_t,则无法保证标准typedef unsigned int uint32_t;转换类型指标不正确。例如,对于32位longint,可以typedefunsigned

对于十六进制,请使用PRIx32PRIX32

详细说明:

宏将映射到字符串文字,其中包含适合您平台的转换说明符,可以是"u"。请注意,必须在前提部分中给出%。连接相邻字符串文字的标准C功能将生成最终的格式字符串。没有运行时开销。

答案 1 :(得分:3)

唯一不对的是你的格式字符串。由于这些是无符号数字,因此您应该使用%u而不是%d,假设uint32_t映射到编译器上的unsigned int(除非您的目标是8位或16位处理器)。

如果您希望确保代码可移植到int类型不是32位宽的系统,则需要使用PRIu32宏(或其他PRI*32宏,例如PRIx32(十六进制)defined in inttypes.h

您可以使用宏代替格式说明符,如下所示:

printf("IP1: %s ------> Integer: %" PRIu32 "\n",IP1,integer_ip);

答案 2 :(得分:3)

正如其他人所提到的,%d格式说明符用于打印已签名的int。您传递的值是未签名的。使用错误的格式说明符会调用undefined behavior

您需要使用%u格式说明符将值打印为unsigned。

更好的是,使用%x格式说明符将值打印为无符号十六进制。这样,每对十六进制字符对应于IP地址的一个字节,使其更易于阅读。

编辑:

但是,C标准并不保证int至少为32位。您需要使用PRIu32PRIx32宏来获取uint32_t的正确格式说明符:

printf("%" PRIx32 "\n", integer_ip);

答案 3 :(得分:1)

htonl返回32位无符号整数。

用于打印值的格式说明符%d适用于签名整数值。

使用适合数据类型(%u)的格式说明符,值将显示为正无符号数。