ntohl() vs htonl() in Little Endian
Asked Answered
B

2

6

Kindly clarify my doubt as i got so confused with the below stuff and i couldnt get a clean anwser any where else on net.

#include<stdio.h>
int main()
{
   int a = 0x44332211;
   printf("Network - 0x%x\n", htonl(a));// Host to network
   printf("Host    - 0x%x\n", ntohl(a));// Network to host
   return 0;
}

Output:

 Network - 0x11223344   
 Host    - 0x11223344  

Here htonl(0x44332211) => i am converting little endian(LE) to BE. So output will be 0x11223344. That i understood. My problem is with ntoh(). Now ntohl(0x44332211) => what?

Here i am executing both the commands on 1 terminal. So host to network, ie hton() means my terminal to network. That makes sense. But here ntohl() means what? ntohl() comes into picture if we have:

a PC A----(ie hton)sending data over network------>(ie ntoh) to PC B?

Also ntoh expects a network byte order ie Big endian. Kindly intepret what ntohl() means above and why its printed same as 0x11223344 and why not 0x44332211?

Brahear answered 7/4, 2013 at 14:58 Comment(0)
C
17

Assuming your program is running on a little-endian machine (e.g. x86), ntohl(a) will return 0x11223344 (i.e. it will flip the byte ordering of your 0x11223344 value, just like htonl() does).

On the other hand, if your program is running on a big-endian machine (e.g. a PowerPC Mac), then ntohl(a) and htonl(a) will both return a, verbatim, since the machine's internal/host format is already the same as the network format.

There's also the (at least theoretical) possibility that your program is running on some unusual hardware that uses a numeric representation that is neither big-endian nor little-endian. In that case, the htonl() and ntohl() functions for that environment would have been programmed to do the right thing (whatever that might be) to convert that machine's internal representation to the standard network representation (which is big-endian) and back.

The expected usage pattern for these function is this:

  • Anytime you are about to send a long to the network, call htonl() on it and send that value instead.
  • Anytime you have just received a long from the network, call ntohl() on it and use that value instead.

That way any variances between the host computer's numeric representation and the network/big-endian representation are automatically handled for you inside htonl() and ntohl(), and you don't have to worry about writing (and testing!) separate conversion code for every computer architecture your program might possibly ever run on.

Carycaryatid answered 7/4, 2013 at 16:38 Comment(0)
A
13

Just stumbled upon this post. I agree with Jeremy's answer, but just wanted to add one more point: When in doubt, go to the source code. If you look at ntoh() and hton() definition in GCC library:

<netinet/in.h>

#  if __BYTE_ORDER == __LITTLE_ENDIAN
#define ntohl(x)     __bswap_32 (x)
#define htonl(x)     __bswap_32 (x)
#endif

So, both ntohl() and htonl() are merely byte swaps defined in byteswap.h. That is why your output is the same for both these macros.

Now, why are they same ??? Well, the author intended ntohl() to be called on Network Endian Data (typically contents of a received packet buffer) and similarly, htonl() to be called on Host Endian Data (data written by the host).

In your case, you are calling both these macro's on the same Host Endian data and that is the problem.

Guess I am late to reply. However, I hope the next visitor finds this answer useful :)

Antidromic answered 2/7, 2015 at 0:43 Comment(3)
Note that the defines and header files are architecture-specific. You’re only looking at a small subset of GCC’s source code if you look at the headers that are installed for natively compiling code on your own machine!Washburn
In a world where big-endian and little-endian are the only two formats, switching between the two formats is always a simple byte-level reverse of the array. The inverse operation of reversing an array is reversing the array (same operation). So there would be no need to have both ntoh*() and hton*(). The important point is that the API supports a scenario where the host’s byte order is neither big-endian or little-endian, in which case the inverse of the conversion might not be the same as the conversion.Washburn
The terminology “big and little endian” comes right out of a DARPA memo, describing byte orders. It is a document worth to read, as it contains many references to architectures now long dead: rfc-editor.org/ien/ien137.txt However, all of them had the property that whatever mixed order they had, ntoh*() and hton*() will always only swap elements, and therefore be identical; there's no known architecture where you e.g. rotate a 32 bit word by 8 bits to the left to get to the network byte order, and rotate by 8 bits to the right to get back to host order.Landgrabber

© 2022 - 2024 — McMap. All rights reserved.