Best way to check endianness at run-time?

Started by
17 comments, last by wintertime 11 years, 1 month ago

The same code can generally compile and run without problems on systems with diverse endianness (provided it's compiled for the appropriate targets). It's usually only something that you need to worry about when dealing with data between machines, and in that case you're better off using a compile-time macro that ensures that data is in the correct format or else is converted.

In order to encounter endianness problems in the code itself you'd have to get up to the same flavor of hackery that's going on in your test function there, which probably isn't good, and at least should be a rare occurrence.

Long story short, if it's not causing errors then don't mess with it.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
Advertisement

As also have been mentioned above, there is a risk that you are falling into a common trap here. Data (or protocols) can be little endian or big endian, but you should never worry about what the current machine/system has.

Please read The byte order fallacy, which I think summarizes it all perfectly!

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

Nice link. That sums it up quite definitively.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Or just use htonl/ntohl etc. to write the values in a standardised order. That code should work on all machines.

I would be wary of pretending to support platforms unless you build and test on them. I don't mean to say that you should write unportable code, but don't think that patchwork of untested preprocessor branches is writing portable code.

Thanks for all the info, you've all gave me different aspects to consider when I decide to switch my map format over to binary. Think I'm gonna save that task for after mid-terms though.

As also have been mentioned above, there is a risk that you are falling into a common trap here. Data (or protocols) can be little endian or big endian, but you should never worry about what the current machine/system has.

Please read The byte order fallacy, which I think summarizes it all perfectly!

I was also going to link to that article, but you beat me to it. For the use-case being described here, i think it's pretty accurate. However, as much respect as I have for all the Bell Labs folks, there is more to the story. In the ideal world where computers are infinitely fast, reading and writing every multi-byte value one byte at a time may be great. For those of us making games that need to load 100s of MBs with minimal delay -- not so much. I'd love to ignore the endianness of each platform we support, and serialize all data in one consistent format. But then we'd be iterating over all of that data at load time, instead of loading up a block of memory and doing pointer fixup.

All of that said, our solution is exactly as frob has indicated: We just #define it at compile time. We need to declare lots of things about each platform we support, we just add endianness to the list. It's really not hard. The #if/#elif chain for each of those decisions always looks like:


#if PLATFORM_WIN64
#define LITTLE_ENDIAN
#elif PLATFORM_PS3
#define BIG_ENDIAN
#else
#error Need to specify endianness for new platform!
#endif

I have some issues with that "The byte order fallacy" post, and since I can't post on his blog, I'm going to leave my comments here:

1. He claims his code "computes a 32-bit integer value regardless of the local size of integers" which is not quite correct. If an int is not 32-bits (particularly, if it's less than 25 bits), his code is invoking undefined behavior (shifting an N-bit number by N or more bits is undefined behavior).

2. He only talks about the simplest case: reading/writing ints. Other data types, like float or double, can't be magically written or read like he shows.

I can't think of other nitpicks. In general, I think he makes a good point, but I think he's being overly critical of the endian-specific method while not being critical enough of his own version. If he's going to be critical, he should be critical to both.

[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Both of your problems is not only a problem with the cleaner always shifting code but also with the #ifdef BIGENDIAN twiddlings and there its maybe not even tested.

1. That can easily be fixed in both with explicit casts to int32_t before shifting.

2. With that you would probably just do a pointer cast. Floats and doubles are ultimately just some data bytes you read in too.

This topic is closed to new replies.

Advertisement