Slightly different requirement: I need a test like this in a program build configure script to determine whether the compile target machine is bit or little endian, without executing code. The script must deposit #define HAVE_LITTLE_ENDIAN 1
into a config.h
header, or else #define HAVE_LITTLE_ENDIAN 0
.
The compile target machine may be different from the build machine, since we may be cross-compiling, which also explains why the test mustn't try to run any compiled code. It is out of the question to have a little C program with a printf
statement that spits out the answer.
A possible solution is this. We generate a file called conftest.c
which contains this:
#define USPELL(C0, C1, C2, C3) \
((unsigned) C0 << 24 | \
(unsigned) C1 << 16 | \
(unsigned) C2 << 8 | (unsigned) C3)
unsigned x[6] = {
0,
USPELL('L', 'I', 'S', 'P'),
USPELL('U', 'N', 'I', 'X'),
USPELL('C', 'O', 'R', 'E'),
USPELL('D', 'W', 'I', 'M'),
0
};
Now, we compile this to conftest.o
using:
$ /path/to/cross-compiling/cc conftest.c -c
Then we run:
$ strings conftest.o
PSILXINUEROCMIWD
If the string PSILXINUEROCMIWD
occurs, the target is little-endian. If the string LISPUNIXCOREDWIM
occurs, it is big-endian. If neither string occurs or, even more astonishingly, both do, then the test has failed.
This approach works because the "fourcc" constants calculated in the program have machine-independent values, denoting the same integers regardless of endianness. Their storage representation in the object file follows the endianness of the target system, and that is visible via the character-based view under strings
.
The two zero guard words ensure that the string is isolated. That isn't strictly necessary, but it ensures that the string we are looking for is not embedded in some other string, meaning that strings
will output it on a line by itself.
P.S. the USPELL
macro doesn't parenthesize the argument insertions because it's crafted for this specific purpose, not for re-use.