Bhaskar
Bhaskar

Reputation: 2723

Same output for htonl() and ntohl() on an integer

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

Answers (4)

Steve Jessop
Steve Jessop

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

kriss
kriss

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

Brian Roach
Brian Roach

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

Alok Singhal
Alok Singhal

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

Related Questions