我对inet_pton()
函数感到困惑。根据{{3}}
此功能将字符串 src 转换为af地址族中的网络地址结构,然后将网络地址结构复制到 dst 。 af参数必须是AF_INET或AF_INET6。 dst 以网络字节顺序编写。
因此该函数产生网络字节顺序值。但是我得到了这段代码:
struct sockaddr_in a;
char sip[20];
inet_pton(AF_INET, "192.168.0.182", (void *)&a.sin_addr);
inet_ntop(AF_INET, (void *)&a.sin_addr, sip, 20);
printf("htonl:%08x\n", htonl(a.sin_addr.s_addr));
printf("inet_pton:%08x\n", a.sin_addr.s_addr);
printf("inet_ntop:%s\n", sip);
输出:
htonl:c0a800b6
inet_pton:b600a8c0
inet_ntop:192.168.0.182
inet_pton
的输出为b6.00.a8.c0
,它转换为182.0.168.192
,它也与htonl
的输出不同。
由于htonl
将主机字节顺序转换为网络字节顺序,所以如果inet_pton
产生网络字节顺序,我想它们的输出应该相同吗?这是否意味着inet_pton
实际上产生了主机字节顺序?
如果inet_pton
已经产生了network byte order
,为什么我需要htonl
才能获得正确的值?
答案 0 :(得分:3)
是的,inet_pton
按照网络顺序将地址字节放入目标缓冲区。让我们来看一个例子,看看会发生什么。使用您的地址“ 192.168.0.182”,inet_pton
会产生以下四个字节:
c0 a8 00 b6 (hex)
192 168 0 182 (dec)
是网络字节顺序。然后,您致电htonl
(实际上并不正确-您应该致电ntohl
将从网络订单转换为主机订单,但正如@ZanLynx指出的那样,两者x86上的功能相同),您可以将字节重新排序为:
b6 00 a8 c0
但是随后您将表单以printf
的格式传递给%x
。这告诉printf
将四个字节解释为单个32位整数,但是x86是一点字节顺序的机器,因此当将四个字节作为整数加载时,b6
是最低顺序的字节而c0
是最高的,它会产生您所看到的:
htonl:c0a800b6
因此,通常,如果您具有网络形式的IPv4地址,并且想要按对您(作为程序员)“有意义”的顺序快速显示(用于调试或其他方式),则可以使用:
printf("%x\n", ntohl(a.sin_addr.s_addr));
您还可以按网络顺序显示单个字节(这是完全相同的东西,但可能更容易缠住您的头),只需使用unsigned char *
(或等效的{{1} } uint8_t *
中的}来打印各个字节:
<stdint.h>
(您需要在此处使用无符号类型,以避免符号扩展。在上面的语句中,每个字符将在对uint8_t *ipp = (void *)&a.sin_addr.s_addr;
printf("%02x %02x %02x %02x\n", ipp[0], ipp[1], ipp[2], ipp[3]);
的调用中提升为int
。如果您已签名{ {1}}包含0xc0,通常会将其符号扩展到32位printf
中:0xffffffc0。或者,您可以使用格式规范{{1 }}明确告诉char
,您实际上是在将它传递给int
;然后,它只会查看每个提升的"%02hhx"
的最低顺序字节。)