I got confused with the inet_pton()
function. According to the 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.
So the function produces a network byte order value. But I got this code:
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);
output:
htonl:c0a800b6
inet_pton:b600a8c0
inet_ntop:192.168.0.182
the output of inet_pton
is b6.00.a8.c0
, which converts to 182.0.168.192
, and it's also different from the output of htonl
.
Since htonl
converts host byte order to network byte order, so if inet_pton
produces network byte order, I suppose their outputs should be the same? Does it mean that inet_pton
actually produces host byte order?
if inet_pton
already produces network byte order
, why do I need htonl
to get the right value?
Yes, inet_pton
puts the address bytes into the destination buffer in network order. Let's go through an example to see what happens. Using your address of "192.168.0.182", inet_pton
produces these four bytes:
c0 a8 00 b6 (hex)
192 168 0 182 (dec)
That is network byte order. When you then call htonl
(which is not actually correct -- you should be calling ntohl
to convert from network order to host order but as @ZanLynx pointed out, the two functions are identical on x86), you re-order the bytes to:
b6 00 a8 c0
But then you pass that form to printf
with %x
as the format. That tells printf
to interpret the four bytes as a single 32-bit integer, but x86 is a little endian machine, so when it loads the four bytes as an integer, the b6
is the lowest order byte and the c0
is the highest, which produces what you saw:
htonl:c0a800b6
So, in general, if you have an IPv4 address in network form, and you want to quickly display it (for debugging or whatever) in an order that "makes sense" to you (as a programmer) you would use:
printf("%x\n", ntohl(a.sin_addr.s_addr));
You could also display the single bytes as they reside in network order (which is really the exact same thing but may be easier to wrap your head around), just use an unsigned char *
(or equivalently uint8_t *
from <stdint.h>
) to print the individual bytes:
uint8_t *ipp = (void *)&a.sin_addr.s_addr;
printf("%02x %02x %02x %02x\n", ipp[0], ipp[1], ipp[2], ipp[3]);
(You need to use an unsigned type here to avoid sign extension. In the above statement, each char will be promoted to an int
in the call to printf
. If you have a signed char
containing, say, 0xc0, it will typically be sign-extended into a 32-bit int
: 0xffffffc0. As an alternative, you can use the format specification "%02hhx"
which explicitly tells printf
that you are really passing it a char
; then it will only look at the lowest order byte of each promoted int
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With