Is there a programmatic way to detect whether or not you are on a big-endian or little-endian architecture? I need to be able to write code that will execute on an Intel or PPC system and use exactly the same code (i.e. no conditional compilation).
Unless you're using a framework that has been ported to PPC and Intel processors, you will have to do conditional compiles, since PPC and Intel platforms have completely different hardware architectures, pipelines, busses, etc. This renders the assembly code completely different between the two.
As for finding endianness, do the following:
short temp = 0x1234;
char* tempChar = (char*)&temp;
You will either get tempChar to be 0x12 or 0x34, from which you will know the endianness.
Declare an int variable:
int variable = 0xFF;
Now use char* pointers to various parts of it and check what is in those parts.
char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;
Depending on which one points to 0xFF byte now you can detect endianness. This requires sizeof( int ) > sizeof( char ), but it's definitely true for the discussed platforms.
Please see this article:
Here is some code to determine what is the type of your machine
int num = 1; if(*(char *)&num == 1) { printf("\nLittle-Endian\n"); } else { printf("Big-Endian\n"); }
See Endianness - C-Level Code illustration.
// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };
ENDIANESS CheckArchEndianalityV1( void )
{
int Endian = 0x00000001; // assuming target architecture is 32-bit
// as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least Significant Byte) = 0x01
// casting down to a single byte value LSB discarding higher bytes
return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
}
You can do it by setting an int and masking off bits, but probably the easiest way is just to use the built in network byte conversion ops (since network byte order is always big endian).
if ( htonl(47) == 47 ) {
// Big endian
} else {
// Little endian.
}
Bit fiddling could be faster, but this way is simple, straightforward and pretty impossible to mess up.
How about this?
#include <cstdio>
int main()
{
unsigned int n = 1;
char *p = 0;
p = (char*)&n;
if (*p == 1)
std::printf("Little Endian\n");
else
if (*(p + sizeof(int) - 1) == 1)
std::printf("Big Endian\n");
else
std::printf("What the crap?\n");
return 0;
}
What operations are you planning on doing where endianness makes a difference? All standard arrithmetic, array manipulation etc. operations will be portable across the different architectures, as the differences will be taken care of for you by the different platform's compilers.
I would do something like this:
bool isBigEndian() {
static unsigned long x(1);
static bool result(reinterpret_cast<unsigned char*>(&x)[0] == 0);
return result;
}
Along these lines, you would get a time efficient function that only does the calculation once.
I don't like the method based on type punning - it will often be warned against by compiler. That's exactly what unions are for !
int is_big_endian(void)
{
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
The principle is equivalent to the type case as suggested by others, but this is clearer - and according to C99, is guaranteed to be correct. gcc prefers this compared to the direct pointer cast.
This is also much better than fixing the endianness at compile time - for OS which support multi-architecture (fat binary on Mac os x for example), this will work for both ppc/i386, whereas it is very easy to mess things up otherwise.
This is normally done at compile time (specially for performance reason) by using the header files available from the compiler or create your own. On linux you have the header file "/usr/include/endian.h"
You can also do this via the preprocessor using something like boost header file which can be found boost endian
Here's another C version. It defines a macro called wicked_cast()
for inline type punning via C99 union literals and the non-standard __typeof__
operator.
#include <limits.h>
#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif
#define wicked_cast(TYPE, VALUE) \
(((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)
_Bool is_little_endian(void)
{
return wicked_cast(unsigned char, 1u);
}
If integers are single-byte values, endianness makes no sense and a compile-time error will be generated.
I surprised no-one has mentioned the macros which the pre-processor defines by default. While these will vary depending on your platform; they are much cleaner than having to write your own endian-check.
For example; if we look at the built-in macros which GCC defines (on an X86-64 machine):
:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1
On a PPC machine I get:
:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1
(The :| gcc -dM -E -x c -
magic prints out all built-in macros).