问题
In regards to htonl and ntohl. When would either of these two lines of code evaluate to false.
htonl(x) == ntohl(x);
htonl(ntohl(x)) == htonl(htonl(x));
In other words, when are these two operations not equivalent on the same machine? The only scenario I can think of is a machine that does not work on 2's complement for representing integers.
Is the reason largely historical, for coding clarity, or for something else?
Do any modern architectures or environments exists today where these converting to and from network byte order on the same machine is not the same code in either direction?
回答1:
I wrote a TCP/IP stack for a UNIVAC 1100 series mainframe many years ago. This was a 36 bit, word addressable computer architecture with 1's complement arithmetic.
When this machine did communications I/O, 8 bit bytes arriving from the outside world would get put into the lower 8 bits of each 9 bit quarter-word. So on this system, ntohl() would squeeze 8 bits in each quarter word down into the lower 32 bits of the word (with the top 4 bits zero) so you could do arithmetic on it.
Likewise, htonl() would take the lower 32 bits in a word and undo this operation to put each 8 bit quantity into the lower 8 bits of each 9 bit quarter word.
So to answer the original question, the ntohl() and htonl() operations on this computer architecture were very different from each other.
For example:
COMP* . COMPRESS A WORD
LSSL A0,36 . CLEAR OUT A0
LSSL A1,1 . THROW AWAY TOP BIT
LDSL A0,8 . GET 8 GOOD ONE'S
LSSL A1,1 .
LDSL A0,8 .
LSSL A1,1 .
LDSL A0,8 .
LSSL A1,1 .
LDSL A0,8 .
J 0,X9 .
.
DCOMP* . DECOMPRESS A WORD
LSSL A0,36 . CLEAR A0
LSSL A1,4 . THROW OUT NOISE
LDSL A0,8 . MOVE 8 GOOD BITS
LSSL A0,1 . ADD 1 NOISE BIT
LDSL A0,8 . MOVE 8 GOOD BITS
LSSL A0,1 . ADD 1 NOISE BIT
LDSL A0,8 . MOVE 8 GOOD BITS
LSSL A0,1 . ADD 1 NOISE BIT
LDSL A0,8 . MOVE 8 GOOD BITS
J 0,X9 .
COMP is the equivalent to ntohl() and DCOMP to htonl(). For those not familiar with UNIVAC 1100 assembly code :-) LSSL is "Left Single Shift Logical" a registers by a number of positions. LDSL is "Left Double Shift Logical" a pair of registers by the specified count. So LDSL A0,8 shifts the concatenated A0, A1 registers left 8 bits, shifting the high 8 bits of A1 into the lower 8 bits of A0.
This code was written in 1981 for a UNIVAC 1108. Some years later, when we had an 1100/90 and it grew a C compiler, I started a port of the BSD NET/2 TCP/IP implementation and implemented ntohl() and htonl() in a similar way. Sadly, I never completed that work..
If you wonder why some of the Internet RFCs use the term "octet", its because some computers in the day (like PDP-10s, Univacs, etc.) had "bytes" that were not 8 bits. An "octet" was defined specifically to be an 8 bit byte.
回答2:
I couldn't find the original draft of the Posix spec, but a recent one found online has a hint.
Network byte order may not be convenient for processing actual values. For this, it is more sensible for values to be stored as ordinary integers. This is known as ‘‘host byte order ’’. In host byte order:
The most significant bit might not be stored in the first byte in address order. **Bits might not be allocated to bytes in any obvious order at all.**
8-bit values stored in uint8_t objects do not require conversion to or from host byte order, as they have the same representation. 16 and 32-bit values can be converted using the htonl(), htons(), ntohl(),and ntohs() functions.
Interesting though is the the following statement is made under the discussion of
The POSIX standard explicitly requires 8-bit char and two’s-complement arithmetic.
So that basically rules out my idea of a 1's complement machine implementation.
But the "any obvious order at all" statement basically suggests that the posix committee at least considered the possibility of posix/unix running on something other than big or little endian. As such declaring htonl and ntohl as differnet implementations can't be ruled out.
So the short answer is "htonl and ntohl are the same implementation, but the interface of two different functions is for future compatibility with the unknown."
回答3:
Not all machines will have the same endianness, and these methods take care of that. It is given that 'network order' is big endian. If you have a machine that is running a big endian architecture and you run ntohl, the output will be the same as the input (because the endianness is the same as network). If your machine is a little endian architecture, ntohl will convert the data from big to little endian. The same can be said about htonl (converts host data to network byte order when necessary). To answer your question, these two operations are not equivalent when you're transmitting data between two machines with different endianness.
来源:https://stackoverflow.com/questions/11617684/when-is-htonlx-ntohlx-or-when-is-converting-to-and-from-network-byte-o