endian-neutral code

Started by
9 comments, last by keethrus 19 years, 8 months ago
I'm not sure how others may handle writing endian-neutral code, but if anybody could give some advice to the following idea I would appreciate it. Would the following code accurately detect the endianness of the sytem it was compiled and ran on?

unsigned int x = 2271560481;   // 0x87654321
if ( ( unsigned char ) x == 33 )   // 0x21
{
   // This system is big-endian
}
else
{
   // This sytem is little-endian
}
Or what about this?

unsigned int x = 2271560481;   // 0x87654321
if ( ( x & 0x000000FF ) == 33 )   // 0x21
{
   // This sytem is big-endian
}
else
{
   // This sytem is little-endian
}
- Jeremiah
Advertisement
  byte SwapTest[2] = { 1, 0 };    if( *(short *) SwapTest == 1 )  {    //little endian    BigEndianSystem = false;    //set func pointers to correct funcs    BigShort = ShortSwap;    LittleShort = ShortNoSwap;    BigLong = LongSwap;    LittleLong = LongNoSwap;    BigFloat = FloatSwap;    LittleFloat = FloatNoSwap;  }  else  {    //big endian    BigEndianSystem = true;    BigShort = ShortNoSwap;    LittleShort = ShortSwap;    BigLong = LongNoSwap;    LittleLong = LongSwap;    BigFloat = FloatSwap;    LittleFloat = FloatNoSwap;  }

That will detect the endian type of the system. More here.
While I can't do any testing to be certain, I believe that approach should work. However, the specific code you gave probably wont. When casting a large integer (unsigned int) to a small integer (unsigned char), the cast will evaluate to the low order byte of the int (which will be the same regardless of endian). Your second approach may work, but will likely be foiled for the same reasons. I think something like this would be appropriate:

unsigned int x = 2271560481; // 0x87654321
unsigned char* px = (unsigned char*)(&x);
if ( px[3] == 33 ) // 0x21
{
// This system is big-endian
}
else
{
// This sytem is little-endian
}
Hello keethrus,

Simple code is to set a 32 bit int to 1.
Then cast the address of the int to a char* and look at first byte.
On little endian the first byte should be 1 on big endian it should be 0.

int endian(1);
int isbig((*((char*)&endain))!=1);
or
int islittle((*((char*)&endain))==1);

Very simple and works on all platfroms.

Lord Bart :)
Why would you even test for this at runtime? Is the endian-ness of the system going to change between runs? Doubtful. I handle endian issues with two things:

1) An endian template class that will flip data around as necessary.

2) A required #define that specifies the endian-ness.

I could do #1 without #2. But I see no reason to weigh down the running code with unnecessary baggage. I'd rather the programmer sit down and define a macro once in the make file / IDE.

That might just be me.
"Anonymous Poster" (wait... it's probably not hist real name ^^) probably got ir right : endianness is a compile time problem, not a runtime one (unless you find a platform where you can switch endianness at run time - this is rare).

Moreover, the only matter which can arise comes from stream reading and writing (file, socket, and so on...). For those, you don't even have to know the endianness of your systme because the standard libc already provide you the way to bypass it :

ntohl(), htonl(), ntohs(), htons()

(for those who don't know : n is network, h is host, l is long (32 bits), s is short (16 bits) and to is... to :P Of course, you may have to create your own functions for other data size (int64, double, and so on)).

Simply to a htonl/htons when writing to the stream, and do the corresponding ntohl/ntohs when reading the data. Using these function, the system already manage the transform if needed and you don't even have to know wether you are little or big endian.

Just my 2 cents ;)

--
Emmanuel
Endianness is a run-time problem only if you're going to be doing low-level IO and/or network IO. The latter is important especially if you're going to support data transfers between machines of different endianness. When sending data, convert it to network byte order, and when receiving data, convert it to your local byte order. If you always make sure that network data is big endian (or little endian, whichever you prefer, but I believe the former is more standard), then you won't have a problem.
Thanks for all the replies! I really appreciate all the feedback.

Some of you said that you can determine endianess at compile-time. Are there any standard C/C++ #defines that you can check for? "#ifdef BIGENDIAN" for example?

- Jeremiah
*bump*

Still wondering about those compiler defines for endianess. :)

- Jeremiah
I may as well point out that the article linked before (well...my article, actually) "stole" the code. Quake 2 dealt with endianness at runtime.

I still don't know why.

If it makes any difference, I'm planning a second version of the article based on compile time defines, templates, and stuff.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

This topic is closed to new replies.

Advertisement