Question on byteorder operations

U

usenet

[Apologies, especially to clc readers who may find this OT]

My experience has been that **ON A GIVEN SYSTEM** htonl and ntohl
always evaluate to the same thing ----- either both of them are no-op
or both of them swap the bytes of the long value that is passed. [Of
course, as you go from a big-endian system to a little-endian system,
the behavior will be different, but that is not what I am talking
about] Same for htons and ntohs.

Can I generalize my observation, or are there any exceptions?

Thanks,
Gus
 
E

Eric Sosman

[Apologies, especially to clc readers who may find this OT]

My experience has been that **ON A GIVEN SYSTEM** htonl and ntohl
always evaluate to the same thing ----- either both of them are no-op
or both of them swap the bytes of the long value that is passed. [Of
course, as you go from a big-endian system to a little-endian system,
the behavior will be different, but that is not what I am talking
about] Same for htons and ntohs.

Can I generalize my observation, or are there any exceptions?

<off-topic reason="grumpy CLC reader">

You are asking "Is every permutation of N elements its
own inverse?" For N=2 the answer is yes, but for N>2 it is
no. For the case N=4 all the machines I've encountered use
one of three permutations which *do* happen to be self-
inverses (either 3210->3210, 0123->3210, or 2301->3210),
but I have not yet encountered all machines ...

</off-topic>
 
G

Gordon Burditt

My experience has been that **ON A GIVEN SYSTEM** htonl and ntohl
always evaluate to the same thing ----- either both of them are no-op
or both of them swap the bytes of the long value that is passed. [Of
course, as you go from a big-endian system to a little-endian system,
the behavior will be different, but that is not what I am talking
about] Same for htons and ntohs.

Can I generalize my observation, or are there any exceptions?

It is *POSSIBLE* that there are exceptions, but I don't know of any
on real systems. ANSI C certainly allows such byteorders (but it
doesn't specify htonl() and ntohl() at all).

There are 8 possible byte orders for sizeof(int) == 3. For those
3 combinations which are not a byte-swap of pairs of specific bytes
nor a noop (123 -> 312, 123 -> 321, 123 -> 231), htonl(x) == ntohl(x)
will be false for some value of x.

There are 24 possible byte orders for sizeof(int) == 4. I haven't
worked out how many combinations make htonl() and ntohl() operate
differently, but one of them would be 1234 -> 2341.


Gordon L. Burditt
 
K

Keith Thompson

There are 8 possible byte orders for sizeof(int) == 3. For those
3 combinations which are not a byte-swap of pairs of specific bytes
nor a noop (123 -> 312, 123 -> 321, 123 -> 231), htonl(x) == ntohl(x)
will be false for some value of x.

6, I believe:

123 132 213 231 312 321
There are 24 possible byte orders for sizeof(int) == 4. I haven't
worked out how many combinations make htonl() and ntohl() operate
differently, but one of them would be 1234 -> 2341.

More generally, n! (n factorial) for sizeof(int) == n. htonl() and
ntohl() will be identical only for permutations that are combinations
of disjoint byte-swaps (as most or all will be in real life).
 
C

CBFalconer

Gordon Burditt wrote: (*** and stripped attributions ***)
My experience has been that **ON A GIVEN SYSTEM** htonl and ntohl
always evaluate to the same thing ----- either both of them are
no-op or both of them swap the bytes of the long value that is
passed. [Of course, as you go from a big-endian system to a
little-endian system, the behavior will be different, but that is
not what I am talking about] Same for htons and ntohs.

Can I generalize my observation, or are there any exceptions?

It is *POSSIBLE* that there are exceptions, but I don't know of
any on real systems. ANSI C certainly allows such byteorders (but
it doesn't specify htonl() and ntohl() at all).

There are 8 possible byte orders for sizeof(int) == 3. For those
3 combinations which are not a byte-swap of pairs of specific
bytes nor a noop (123 -> 312, 123 -> 321, 123 -> 231), htonl(x)
== ntohl(x) will be false for some value of x.

There are 24 possible byte orders for sizeof(int) == 4. I haven't
worked out how many combinations make htonl() and ntohl() operate
differently, but one of them would be 1234 -> 2341.

Bear in mind that the networks operate on octets, not bytes. The
consistent thing on the network end is that the most significant
octet comes first. You have to guarantee that regardless of your
systems perversions (deliberate word choice :) and CHAR_BIT value.
 
G

Gordon Burditt

There are 8 possible byte orders for sizeof(int) == 3. For those
6, I believe:

123 132 213 231 312 321

123 is a no-op
132 is a byte-swap
213 is a byte-swap
231
312
321 is a byte-swap (I was wrong including it above)

so there are only two combinations where htonl(x) != ntohl(x) for
some value of x.

Gordon L. Burditt
 
K

Keith Thompson

123 is a no-op
132 is a byte-swap
213 is a byte-swap
231
312
321 is a byte-swap (I was wrong including it above)

so there are only two combinations where htonl(x) != ntohl(x) for
some value of x.

Please don't snip attributions. ("There are 8 possible ..." was
yours; "6, I believe" was mine.)

I believe the above is correct -- but I don't know of any
implementations with sizeof(int)==3.

For sizeof(int)==4, I *think* that 8 of the 24 permutations make
htonl(x) != ntohl(x), specifically the ones for which 3 of the 4 bytes
are rotated one position. I doubt that any real-world implementations
use any of them. (The only ones I've heard of are 1234, 4321, and
3412.)
 
C

CBFalconer

Keith said:
.... snip ...

For sizeof(int)==4, I *think* that 8 of the 24 permutations make
htonl(x) != ntohl(x), specifically the ones for which 3 of the 4
bytes are rotated one position. I doubt that any real-world
implementations use any of them. (The only ones I've heard of
are 1234, 4321, and 3412.)

But they don't matter. All the implementor of htonl and ntohl
needs to know is the network order. He does the rest of the work
by shifting (or multiplying and dividing by 256) unsigned int
values, and masking off a portion. The code can be made completely
portable, as long as the 4 octets on the network are sufficient to
express the range of an int.
 
K

Keith Thompson

CBFalconer said:
But they don't matter. All the implementor of htonl and ntohl
needs to know is the network order. He does the rest of the work
by shifting (or multiplying and dividing by 256) unsigned int
values, and masking off a portion. The code can be made completely
portable, as long as the 4 octets on the network are sufficient to
express the range of an int.

Agreed.

I think this whole discussion is mostly an academic exercise. If
htonl and ntohl were defined to behave identically, it probably
wouldn't affect any real-world systems, since they almost certainly do
so already. But since they're really doing two logically distinct
things (converting to and from network byte order), it's still a
cleaner design to have two separate functions, and they're nothing to
be gained by assuming that they behave the same way.

On the other hand, it does provide an answer to the question "I used
the wrong function; why does it still work?"

(Of course htonl() and ntohl() aren't standard C, but their behavior
can easily be discussed in standard C terms.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top