Sign in to follow this  
keethrus

endian-neutral code

Recommended Posts

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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
}

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
"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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Well, it seems to me that that quick test for endianness at runtime is extremely simple and it works. You could probably just test for endianness once at startup, change some function pointers or whatever, and you have a simple and perfect fix to your endianness problem.
In doing some research into compiler defines for endianness at compile-time, it seems that there really isn't any simple way to do it. You end up with a lot of #ifdefs and some pretty ugly code. And I'm not sure if you can have 100% confidence your code will compile correctly on any machine.
Anyway, The only advantage I see of going the compile-time route is if you just *absolutely* need the fastest code possible. But I seriously doubt loading 32-bit integers from a file and making sure they're endian-correct is going to be in the speed-critical section of anyone's code. But of course you never know. :)

- Jeremiah

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this