Sign in to follow this  
Alundra

Safe endian macro

Recommended Posts

Hi,

Here what I'm curently using :

#if defined( __m68k__ ) || defined( mc68000 ) || defined( _M_M68K ) || ( defined( __MIPS__ ) && defined( __MISPEB__ ) ) || \
    defined( __ppc__ ) || defined( __POWERPC__ ) || defined( _M_PPC ) || defined( __sparc__ ) || defined( __hppa__ )
    #ifndef ENDIAN_BIG
      #define ENDIAN_BIG
    #endif // ENDIAN_BIG
#else
    #ifndef ENDIAN_LITTLE
      #define ENDIAN_LITTLE
    #endif // ENDIAN_LITTLE
#endif // ENDIAN

Is it safe enough or more check is needed ?

Thanks

 

Share this post


Link to post
Share on other sites

An M68k? Sparc? The freaking HPPA?? What on earth are you coding that requires this level of flexibility? (If it's a generic header for 'everything', stop and do something else that is grounded in reality.)

Even in the multi-system *nix world that tends to develop that type of laundry-list of devices, they are typically added individually as each new system adds support.

I suppose if the original code was starting with a fork of the already cross-platform Frozen Bubbles or something similar, that might make some sense.

Share this post


Link to post
Share on other sites

This, of course, is going to break if (and when) a new architecture comes out that you haven't already accounted for.

 

How about just storing a number in a short or an int, then checking the value of it's bytes and converting if needed at runtime?  That's similar to the method used by e.g the Quake engine games and it will work irrespective of what future architectures might appear (https://github.com/id-Software/Quake/blob/master/WinQuake/common.c#L1127):

byte swaptest[2] = {1, 0};

if (*(short *) swaptest == 1)
	bigendien = false;
else bigendien = true;

Share this post


Link to post
Share on other sites

I work a lot with embedded, and in particular files and memory dumps from embedded systems. In my experience, it doesn't matter that much if you are running on one or the other, what matters is if you are working with files/data from the other one. Almost all files/dumps/structures/whatever have some magic number header where we just do something like

 

var val = reader.ReadUInt32();

 

if(val == 0xAABBCCDD)
{
  reader.SwitchEndianess = false;
}
else if(val == 0xDDCCBBAA)
{
  reader.SwitchEndianess = true;
}
else

{

 throw new InvalidDataException();

}

 

I suppose it could matter if you try to write a file with a defined byte order though.

 

[Edit]

Also, many processors have runtime switchable endianess, including most ARMs if I'm not mistaken. :)

Edited by DvDmanDT

Share this post


Link to post
Share on other sites

 

This, of course, is going to break if (and when) a new architecture comes out that you haven't already accounted for.

 

How about just storing a number in a short or an int, then checking the value of it's bytes and converting if needed at runtime?  That's similar to the method used by e.g the Quake engine games and it will work irrespective of what future architectures might appear (https://github.com/id-Software/Quake/blob/master/WinQuake/common.c#L1127):

byte swaptest[2] = {1, 0};

if (*(short *) swaptest == 1)
	bigendien = false;
else bigendien = true;

 

Yeah, I vote for this as well. I just run the following at startup and leave it at that:

bool Endian::isSystemLittleEndian()
{
	short number = 0x1;
	char *numPtr = (char*)&number;
	return (numPtr[0] == 1);
}

Share this post


Link to post
Share on other sites
The downside with all the above suggested runtime techniques is just that - they're runtime.

In my experience there are only three places where endianess matters - when I'm loading a file off of disk with an unknown endian format, when I'm dealing with network packets, and when I'm writing out data to be used on another platform.

The first one should be minimized - and eliminated if possible - by always making sure a platform loads native assets and save games and whatnot. Now, during development you'll want to support it so you can transfer savegames and assets between platforms - but your release build probably doesn't need to handle it. This is usually handled with having a magic number at the start of your file header and, if it doesn't match on read, endian swapping it and checking again. It doesn't need to know what endianess it is - only if it's different then the asset.

The second one can be done at compile time since you know what endianess your network packets will have, and the endianess of your machine - so no runtime choices have to be made.

The third is arguably the only one that needs to know what its endianess is - but this is also usually a tool thing, and tools can afford to be slower then a game.

So in short - you don't need to know at runtime in a game. You might need to know at runtime in a tool. Basically - you want to avoid a bunch of "should I swap?" checks every time you read in a small amount of data from your files as that will hurt loading times. Edited by SmkViper

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