ntohl() vs htonl() in Little Endian

Subi Suresh picture Subi Suresh · Apr 7, 2013 · Viewed 11k times · Source

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?

Answer

Jeremy Friesner picture Jeremy Friesner · Apr 7, 2013

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.