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
}
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 }
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);
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.
"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.
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?