Reputation: 2723
I ran the following program on little-endian [LE] machine [Linux, Intel processor]. I am unable to explain the 3 outputs in below code snippet. Since machine is LE, the value of a
is stored as 0x78563412
. When printing, it is displaying its actual value. Since its an LE machine, I expect ntohl()
to be a no-op and display 0x78563412
, which it is doing. However, I expect 0x12345678
for 2nd print statement containing htonl()
. Can someone please help me understand why they are same?
int main()
{
int a = 0x12345678;
printf("Original - 0x%x\n", (a));
printf("Network - 0x%x\n", htonl(a));
printf("Host - 0x%x\n", ntohl(a));
return 0;
}
Output:
Original - 0x12345678
Network - 0x78563412
Host - 0x78563412
Upvotes: 16
Views: 46188
Reputation: 279245
Since its an LE machine, I expect
ntohl()
to be a no-op
That's the mistake. Network byte order is big-endian, host byte order is little-endian. Therefore, both ntohl
and htonl
return a byte-swapped version of their input.
Remember, the point of htonl
is that you can take an integer on the host, then write:
int i = htonl(a);
and the result is that the memory of i
, when interpreted using network byte order, has the same value that a
does. Hence, if you write the object representation of i
to a socket and the reader at the other end expects a 4-byte integer in network byte order, it will read the value of a
.
and display
0x78563412
Is this what you intended to write? If ntohl
were a no-op (or rather, an identity function), then your third line necessarily would print the same thing as your first line, because you would have ntohl(a) == a
. This is what happens on big-endian implementations, where your program prints:
Original - 0x12345678
Network - 0x12345678
Host - 0x12345678
Upvotes: 26
Reputation: 24157
In your program when you write int a;
you know that a
contains an host ordered integer, the program doesn't know that. You could as easily provide an int already containing a value in network order. Of course if you use any arithmetic operator on a value that is not in host order, the result will be incorrect from a network point of view if network order is not the same as host order.
But this is not so far fetched, the network ordered values are often kept exactly that way in low level structures, before being sent or just after being received.
What is wrong with your program is that when you call ntohl()
your are promising to the ntohl()
function that the int
you are providing is some value stored in memory in network order. That's the contract. If it's not true, the function won't perform what you expect, and that is what you are seing.
As other explained on most systems (big or little but not stupid-endians) the two functions are usually identical, either a bytes reverse or a no-op.
Upvotes: 0
Reputation: 76898
Because you're passing a
by value and therefore it isn't changed by either of those functions.
You're printing what htonl()
and ntohl()
are returning.
Edit to add: I missed where you thought one would be a no-op. It's not. Both are going to do the exact same thing on a LE machine; reverse the byte ordering. ntohl()
is expecting you to be passing it a network byte ordered int
Upvotes: 6
Reputation: 96121
htonl
and ntohl
are exactly the same functions. They are supposed to satisfy htonl(ntohl(x)) == x
. They are named differently only for documentation (you make it explicit that you are converting from host-to-network or the other way, even if it's the same). So, on a little-endian machine, they both perform byte-swapping, and on a big-endian machine, they are both no-ops.
Upvotes: 19