Portable endianess

H

hantheman

Is this a portable implementation?

#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)

#define htons(A) (A)
#define htonl(A) (A)
#define ntohs(A) (A)
#define ntohl(A) (A)

#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)

#define htons(A) ((((uint16)(A) & 0xff00) >> 8) | \
(((uint16)(A) & 0x00ff) << 8))
#define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))
#define ntohs htons
#define ntohl htohl

#else

#error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."

#endif
 
J

Jeff Schwab

hantheman said:
Is this a portable implementation?

#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)

#define htons(A) (A)
#define htonl(A) (A)
#define ntohs(A) (A)
#define ntohl(A) (A)

#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)

#define htons(A) ((((uint16)(A) & 0xff00) >> 8) | \
(((uint16)(A) & 0x00ff) << 8))
#define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))
#define ntohs htons
#define ntohl htohl

#else

#error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."

#endif

Who said bytes had eight bits?
 
H

Heinz Ozwirk

: hantheman wrote:
: > Is this a portable implementation?
: >
: > #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
: >
: > #define htons(A) (A)
: > #define htonl(A) (A)
: > #define ntohs(A) (A)
: > #define ntohl(A) (A)
: >
: > #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
: >
: > #define htons(A) ((((uint16)(A) & 0xff00) >> 8) | \
: > (((uint16)(A) & 0x00ff) << 8))
: > #define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | \
: > (((uint32)(A) & 0x00ff0000) >> 8) | \
: > (((uint32)(A) & 0x0000ff00) << 8) | \
: > (((uint32)(A) & 0x000000ff) << 24))
: > #define ntohs htons
: > #define ntohl htohl
: >
: > #else
: >
: > #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."
: >
: > #endif
:
: Who said bytes had eight bits?

Who's talking about bytes? The 8 bits you probaly assume to be the number of bits in a (C++-) "byte" are the number of bits in a network octet, which is defined to be 8 bits.

Heinz
 
J

Jeff Schwab

Heinz said:
: hantheman wrote:
: > Is this a portable implementation?
: >
: > #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
: >
: > #define htons(A) (A)
: > #define htonl(A) (A)
: > #define ntohs(A) (A)
: > #define ntohl(A) (A)
: >
: > #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
: >
: > #define htons(A) ((((uint16)(A) & 0xff00) >> 8) | \
: > (((uint16)(A) & 0x00ff) << 8))
: > #define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | \
: > (((uint32)(A) & 0x00ff0000) >> 8) | \
: > (((uint32)(A) & 0x0000ff00) << 8) | \
: > (((uint32)(A) & 0x000000ff) << 24))
: > #define ntohs htons
: > #define ntohl htohl
: >
: > #else
: >
: > #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."
: >
: > #endif
:
: Who said bytes had eight bits?

Who's talking about bytes? The 8 bits you probaly assume to be the number of bits in a (C++-) "byte" are the number of bits in a network octet, which is defined to be 8 bits.

Heinz


Thanks for clarifying. :) Poor assumption on my part.

Another question: Why are you doing all this in the preprocessor?
 
G

Gene Wirchenko

: hantheman wrote:
: > Is this a portable implementation?

#include <winsock.h>
and
#include <winsock2.h>
are. Unless you are implementing Winsock, you should use your
system's header.

[snip]

Sincerely,

Gene Wirchenko
 
S

Stewart Gordon

<snip>

Only if you can rely on the programmer's knowing which endianness
his/her platform is.

Moreover, there might not even be a programmer, but merely someone who's
compiling a program delivered in source form.

I recently did something with this. Basically, I was modifying rayshade
to generate BMP output. I don't have the code over here, but it was
something like:

union EndianBytes {
unsigned char b[4];
short s;
long l;
}

short LEShort(short s) {
EndianBytes e;

e.b[0] = (unsigned char) s;
e.b[1] = (unsigned char) (s >> 8);

return e.s;
}

LEShort converts a short from platform byte-order to little-endian or
vice versa. It's straightforward to write BEShort, LELong and BELong on
the same principle.

Of course it still relies on some standard dimensions (byte = 8 bits,
short = 2 bytes, long = 4 bytes), but it'll work on either BE or LE
platforms without requiring any extra attention or knowledge on the side
of the person writing/compiling a program that uses it.

Stewart.
 
N

Nick Hounsome

Stewart Gordon said:
<snip>

Only if you can rely on the programmer's knowing which endianness
his/her platform is.

I've recently been using QNX and they have a very clean and logical way of
pushing the endianness issue into 'the implementation':

They just provide macros such as ENDIAN_BE16(x), ENDIAN_LE16(x),
ENDIAN_BE32(x) etc..
If you are dealing with an external format that you know to be Bigendian 16
bits then whenever you read it in you convert it with
internal_format = ENDIAN_BE16(external_format) and when you want to send it
out you use
external_format = ENDIAN_BE16(internal_format)

The implementation conditionally compiles the macros to be either a byte
swap or no op depending on the endianness of the system.

Obviously this doesn't actually answer the question of how to determine the
endianness of a system (which cannot portably be done at compile time) but
is a very clean way of keeping all (host) endianness issues hidden away in
one header file and concentrates instead on interface endianness which is as
it should be.
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top