endianness detection
orz

I know Allegro will tell you what the endianness is, as will SDL, and probably autoconf or something. But for code that doesn't use any special installers or libraries with special installers, what's the best way to detect endianness at compile time?

SDL uses this as a backup detector for big endianness:

#if defined(__hppa__) || \
    defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ 
    (defined(__MIPS__) && defined(__MISPEB__)) || \ 
    defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ 
    defined(__sparc__) 

but according to wikipedia, some (rare?) PPC, Sparc, and MIPS systems are little endian instead of big endian.

Some documentation says that windows in little-endian only; if that's correct I could check for _WIN32 and _WIN64.

A google search suggests that on some unix systems there is an endian.h, and on some others there's a sys/endian.h or machine/endian.h. My DJGPP install has a machine/endian.h, but my MINGW install has nothing like it that I see (rpcndr.h includes a line "#define NDR_LOCAL_ENDIAN NDR_LITTLE_ENDIAN", but what is rpcndr.h?).

I think, for my purposes, working on x86 or windows or linux and producing an informative error at compile-time for unrecognized platforms would be good enough. Can anyone tell me how I'm supposed to detect endianness at compile time on linux? Googling mostly produces confusing patches, mailing list archives of arguments (which leave out important details), and articles that deal with the issue at runtime instead.

Jonatan Hedborg

Do you truly need to support those obscure little endian systems?
I know that's not very helpful, but i have no idea how to detect it compile time. Not even sure if it's possible.

Matthew Leverton

Looks like OS X might have an endian macro.

But why not just let the user decide (or override)? And if they don't know, provide a simple test case that can be compiled.

orz
Quote:

Do you truly need to support those obscure little endian systems?
I know that's not very helpful, but i have no idea how to detect it compile time. Not even sure if it's possible.

Obscure little endian systems? My computer is little endian, probably your computer is too. Maybe you mean obscure big endian machines, but that includes, at a guess, 80% of macintoshes, 66% of high end servers, and 50% of embedded chips.

It is kinda important that I support big endian machines for this. And I'd really like the detection to occur at compile time, though I'll probably double-check at runtime. There's no way to check in the C/C++ language, but there are conventions that are supposed to allow you to check with the preprocessor. I'm just trying to find out the details on these conventions, since they're not consistent between platforms.

Quote:

Looks like OS X might have an endian macro.

But why not just let the user decide (or override)? And if they don't know, provide a simple test case that can be compiled.

My plan is to do that for unrecognized systems. But for typical systems, I'd like to have it more automatic than that.

Jonatan Hedborg

Yes, what you said :)
I did not mean to skip endian checking altogether, just those that are not covered by that macro you posted.

orz
Quote:

I did not mean to skip endian checking altogether, just those that are not covered by that macro you posted.

Oh... that makes a lot more sense that what I thought you were saying : )
But I'd like to have something that fails gracefully at compile time if it fails, instead of silently (at least until runtime) producing incorrect stuff, even if failures are rare.

Thomas Harte
Quote:

some (rare?) PPC, Sparc, and MIPS systems are little endian instead of big endian.

The PPC (other than the G5) can switch endianness at runtime. All memory reads are 32bit, so discerning bytes/etc is a matter of reading a 32bit chunk of memory, then picking the byte you want. Endianness is altered by setting an XOR mask for doing that.

Anyway, blah blah blah, how about this:

Uint32 Value32;
Uint8 *VPtr = (Uint8 *)&Value32;

VPtr[0] = VPtr[1] = VPtr[2] = 0; VPtr[3] = 1;

if(Value32 == 1)
   printf("I'm big endian\n");
else
   printf("I'm little endian\n");

orz

That's runtime. My plan is compile-time, with a double-check at runtime check.

Neil Black

What the insert favorite obscenity here is an endian?

Jonatan Hedborg

It's regarding whether or not you crack an egg on the big end or the small end.

But in this case, it's about a silly convention that keeps programmers on the verge of insanity :)
One of them means that multi-byte integers are saved "from left to right" and the other "from right to left".

Peter Hull

Possumdude0: this might explain.

orz: I think it's impossible to detect at compile time because any macro testing happens in the preprocessor and the endianness doesn't become apparent until code generation time.

However, why not write a mini program (along the lines of Thomas's) to run first and output either #define BIG_ENDIAN or #define LITTLE_ENDIAN to a .h file, then include that file in your main program. It would be easy to incorporate this into a makefile.

Of course if you're cross-compiling, that won't work!

Pete

orz
Quote:

orz: I think it's impossible to detect at compile time because any macro testing happens in the preprocessor and the endianness doesn't become apparent until code generation time.

It's impossible to generate that information at compile time, but if predefined symbols or systems headers already know, its possible to check them at compile time. And they generally know. The problem is that every system has different headers and predefines, and no one documents how to check them well, and obscure or not-yet-created environments are impractical to check via that method unless they conform to some more common or pre-existing method of checking. You can check if the system is x86; if so you know that it's little endian. You can check if it's win32. If so, I think that means it's little endian. You can probably, somehow, check if it's a mac; if so, it's big endian. You can check if it's running linux; if so, some header somewhere says whether it's big endian or little endian. I'm trying to find out what the headers and preprocessor symbols are that are necessary to find an endianness 95+% of the time and be correct about it 100% of the time.

Quote:

However, why not write a mini program (along the lines of Thomas's) to run first and output either #define BIG_ENDIAN or #define LITTLE_ENDIAN to a .h file, then include that file in your main program. It would be easy to incorporate this into a makefile.

That's what I'm trying to avoid: an installation step that my users or I will screw up.

Elverion

I don't think checking this during compile time is very practical. What about when endianness is per system rather than per platform? It would be a pain to have to recompile your code for each system not only based on platform, but on endianness as well. Can't you just use run-time checks, which would be far more accurate and easy?

This is what I use.

/* returns true if on big endian, else false */
int BigEndianTest()
{
  unsigned char EndianTest[2] = {1,0};
  short x = *(short *)EndianTest;

  if( x == 1 )
    return false;
  else
    return true;
}

Neil Walker

The only time I've ever needed to worry about endianness is when reading serialised data from files created on another system.

Thread #592785. Printed from Allegro.cc