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

Converting dotted IP to integer using htonl(inet_addr(IP_str)) return negative values for IP Adresses of Class B and C

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

问题是函数 returns 对 class 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 是否在 class A 中。

我该如何解决这个问题?

谢谢?

唯一的问题是您的格式字符串。由于这些是无符号数,您应该使用 %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);

htonl returns 32 位 无符号 整数。

您用来打印值的格式说明符 %d 适用于 有符号 整数值。

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

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

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

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

编辑:

然而,C 标准并不保证 int 至少是 32 位。您需要使用 PRIu32PRIx32 宏来获取 uint32_t:

的正确格式说明符
printf("%" PRIx32 "\n", integer_ip);

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

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

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

如果 uint32_t 不是 typedef unsigned int uint32_t;,则不能保证标准 %u 转换类型指定器是正确的。例如,对于 32 位 longint,它可以 typedefed 到 unsigned 中的任何一个。

对于十六进制,使用 PRIx32PRIX32

详情:

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