Safe endian macro

Started by
9 comments, last by SmkViper 9 years ago

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

Advertisement

This is what I use. You might be able to extract extra checks from this. Note the disclaimer.

http://files.sandmines.org/sml_endian.hpp

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.)

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

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.

I take a very different approach to platform dependent values in headers. Instead of using a mess of ifdefs, I have a separate platform.h header for every supported platform in a separate directory and have the build system put the relevant platform header in the include path. So there might be a windows/platform.h header where LITTLE_ENDIAN is defined and a pdp10/platform.h header where BIG_ENDIAN is defined.

Conveniently, the next version of boost is slated to have an endian library, so you may want to raid the development version of their header for their definitions or just wait until the current version is finalized.

YAGNI. Write code when you need to. Detect the platforms that you actually support. Use an else-error to notify you when you need to support/detect a new platform.
#if FOO
# define ENDIAN_BIG
#elif BAR
# define ENDIAN_LITTLE
#else
# error "Todo: port to this platform"
#endif

I changed to that, gives a code lines multiplied by 3 for the platform/architecture/endian detection but surely a lot more safe.

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;

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

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. :)

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);
}

This topic is closed to new replies.

Advertisement