C - inet_pton() 不产生网络字节顺序

C - inet_pton() not producing network byte order

我对 inet_pton() 函数感到困惑。根据 man page

This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst. The af argument must be either AF_INET or AF_INET6. dst is written in network byte order.

因此该函数生成网络字节顺序值。但是我得到了这个代码:

 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 才能得到正确的值?

是的,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 地址,并且您希望以 "makes sense" 对您(作为程序员)的顺序快速显示它(用于调试或其他),您将使用:

printf("%x\n", ntohl(a.sin_addr.s_addr));

您还可以显示单个字节,因为它们位于网络顺序中(这实际上是完全相同的,但可能更容易理解),只需使用 unsigned char *(或等效的 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]);

(你需要在这里使用无符号类型以避免符号扩展。在上面的语句中,每个字符将在调用 printf 时被提升为一个 int。如果你有一个signed char contains, say, 0xc0, it is typically will be sign-extended into a 32-bit int: 0xffffffc0. 作为替代方案,您可以使用格式规范 "%02hhx" 明确告诉 printf 你真的传递给它一个 char;然后它只会查看每个提升的 int 的最低位字节。)