Reputation: 11394
Is there a one line macro definition to determine the endianness of the machine? I am using the following code but converting it to macro would be too long:
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char *test_endian = (unsigned char*)&test_var;
return (test_endian[0] == 0);
}
Upvotes: 129
Views: 139883
Reputation: 731
I do not like most of the answers here as they either:
__LITTLE_ENDIAN__
defined unlike GCC)I personally went with wrapping Compiler-specific defines and checking weather they work or not:
// same values as the ones defined by gcc-compatible compilers such as:
// gcc, clang, tcc (mob-devel), icx and other clang-derivatives
#define ENDIAN_LITTLE (1234)
#define ENDIAN_BIG (4321)
#define ENDIAN_PDP (3412)
#if defined(__BYTE_ORDER__)
// if __BYTE_ORDER__ is defined, we can safely use it
// and we can asume that __ORDER_LITTLE_ENDIAN__
// __ORDER_BIG_ENDIAN__ and __ORDER_PDP_ENDIAN__ are also defined
#define ENDIAN_ORDER __BYTE_ORDER__
// TCC mob-devel seems to be missing this one single define
#if defined(__TINYC__) && !defined(__ORDER_PDP_ENDIAN__)
#define __ORDER_PDP_ENDIAN__ ENDIAN_PDP
#endif
// check if our macros match with those predefined
// this will also fail if some of them are missing
#if (ENDIAN_LITTLE != __ORDER_LITTLE_ENDIAN__) || (ENDIAN_BIG != __ORDER_BIG_ENDIAN__) || (ENDIAN_PDP != __ORDER_PDP_ENDIAN__)
#error "Mismatch between ENDIAN_* and __ORDER_*_ENDIAN__ macros detected !"
#endif
#elif defined(_MSC_VER)
// MSVC does NOT predefine anything about Endianess
// and this compiler only suports targets with Little Endian
#define ENDIAN_ORDER ENDIAN_LITTLE
#else
#error "Unable to deremine ENDIAN_ORDER !"
#endif
// May trigger someday for something like Honeywell 316 (aka ENDIAN_BIG_WORD)
// currently nothing I tested really suports this Endianess
#if (ENDIAN_ORDER != ENDIAN_LITTLE) && (ENDIAN_ORDER != ENDIAN_BIG) && (ENDIAN_ORDER != ENDIAN_PDP)
#error "Unknown ENDIAN_ORDER !"
#endif
then I can use it like so:
if (ENDIAN_ORDER == ENDIAN_BIG) {
// do something only on system with Big Endian bit order...
}
or
#if ENDIAN_ORDER == ENDIAN_BIG
// preprocess only on system with Big Endian bit order...
#endif
Proof it works on GCC, Clang, TCC, MSVC: https://godbolt.org/z/c3fancP8j
Upvotes: 1
Reputation: 10197
If you are looking for a compile time test and you are using gcc or clang, you can do:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
See gcc documentation for more information.
Upvotes: 17
Reputation: 2259
#include <stdio.h>
#define CHECK_FOR_ENDIANNESS (*(char*)&(unsigned int){1})
int main() {
if (CHECK_FOR_ENDIANNESS) {
printf("little-endian.\n");
} else {
printf("big-endian.\n");
}
return 0;
}
How It Works
Step #1 Create an unsigned int with a value of 1
+----------+----------+----------+----------+
Memory Address | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
+----------+----------+----------+----------+
Little: | 01 | 00 | 00 | 00 |
+----------+----------+----------+----------+
Big: | 00 | 00 | 00 | 01 |
+----------+----------+----------+----------+
Step #2 Cast the address to a char pointer (focuses on first byte)
+----------+
Memory Address | 0x1000 |
+----------+
Little: | 01 |
+----------+
Big: | 00 |
+----------+
Step #3 Dereference the char pointer to get the value
Little: Returns 1 (for little-endian)
Big: Returns 0 (for big-endian)
Upvotes: 1
Reputation: 587
In C++20 an enum std::endian
in the header <bit>
was introduced:
https://en.cppreference.com/w/cpp/types/endian
#include <bit>
#include <iostream>
int main() {
if constexpr (std::endian::native == std::endian::big)
std::cout << "big-endian\n";
else if constexpr (std::endian::native == std::endian::little)
std::cout << "little-endian\n";
else std::cout << "mixed-endian\n";
}
Upvotes: 4
Reputation: 41753
If boost is available then you can use Boost.Predef
which contains various predefined macros for the target platform including endianness (BOOST_ENDIAN_*
). Yes boost is often thought as a C++ library, but this one is a preprocessor header that works with C as well! It allows you to detect endian in compile time portably
This library defines a set of compiler, architecture, operating system, library, and other version numbers from the information it can gather of C, C++, Objective C, and Objective C++ predefined macros or those defined in generally available headers. The idea for this library grew out of a proposal to extend the Boost Config library to provide more, and consistent, information than the feature definitions it supports. What follows is an edited version of that brief proposal.
For example
#include <boost/predef.h>
// or just include the necessary header
// #include <boost/predef/other/endian.h>
#if BOOST_ENDIAN_BIG_BYTE
#elif BOOST_ENDIAN_LITTLE_BYTE
#elif BOOST_ENDIAN_LITTLE_WORD
...
#endif
More details can be found in BOOST_ENDIAN_*
section
Note that it obviously can't detect bi-endian platforms where the endian can be changed during runtime
The detection is conservative in that it only identifies endianness that it knows for certain. In particular bi-endianness is not indicated as is it not practically possible to determine the endianness from anything but an operating system provided header. And the currently known headers do not define that programatic bi-endianness is available.
Upvotes: 1
Reputation: 177
This question is actual for cpp too, so I asked here.
ONLY #if __cplusplus > 201703L
#include <bit>
#include <iostream>
using namespace std;
int main()
{
if constexpr (endian::native == endian::big)
cout << "big-endian";
else if constexpr (endian::native == endian::little)
cout << "little-endian";
else
cout << "mixed-endian";
}
For more info: https://en.cppreference.com/w/cpp/types/endian
Upvotes: 4
Reputation: 1574
If your compiler supports compound literals and you are pointedly not using C++ you can use
#define BIG_ENDIAN ((*(const char*)&(const int){0x01020304}) == 0x01)
#define LITTLE_ENDIAN ((*(const char*)&(const int){0x01020304}) == 0x04)
This doesn't require the declaration of any runtime variables, which I think makes it a good deal cleaner than most of the other solutions
Upvotes: 1
Reputation: 721
If you dump the preprocessor #defines
gcc -dM -E - < /dev/null
g++ -dM -E -x c++ - < /dev/null
You can usually find stuff that will help you. With compile time logic.
#define __LITTLE_ENDIAN__ 1
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
Various compilers may have different defines however.
Upvotes: 9
Reputation: 3930
Please pay attention that most of the answers here are not portable, since compilers today will evaluate those answers in compilation time (depends on the optimization) and return a specific value based on a specific endianness, while the actual machine endianness can differ. The values on which the endianness is tested, won't never reach the system memory thus the real executed code will return the same result regardless of the actual endianness.
For example, in ARM Cortex-M3 the implemented endianness will reflect in a status bit AIRCR.ENDIANNESS and compiler cannot know this value in compile time.
Compilation output for some of the answers suggested here:
https://godbolt.org/z/GJGNE2 for this answer,
https://godbolt.org/z/Yv-pyJ for this answer, and so on.
To solve it you will need to use the volatile
qualifier. Yogeesh H T
's answer is the closest one for today's real life usage, but since Christoph
suggests more comprehensive solution, a slight fix to his answer would make the answer complete, just add volatile
to the union declaration: static const volatile union
.
This would assure storing and reading from memory, which is needed to determine endianness.
Upvotes: 2
Reputation: 169533
Code supporting arbitrary byte orders, ready to be put into a file called order32.h
:
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul, /* DEC PDP-11 (aka ENDIAN_LITTLE_WORD) */
O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 (aka ENDIAN_BIG_WORD) */
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
You would check for little endian systems via
O32_HOST_ORDER == O32_LITTLE_ENDIAN
Upvotes: 123
Reputation: 239011
If you have a compiler that supports C99 compound literals:
#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
or:
#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)
In general though, you should try to write code that does not depend on the endianness of the host platform.
Example of host-endianness-independent implementation of ntohl()
:
uint32_t ntohl(uint32_t n)
{
unsigned char *np = (unsigned char *)&n;
return ((uint32_t)np[0] << 24) |
((uint32_t)np[1] << 16) |
((uint32_t)np[2] << 8) |
(uint32_t)np[3];
}
Upvotes: 59
Reputation: 2885
Macro to find endiannes
#define ENDIANNES() ((1 && 1 == 0) ? printf("Big-Endian"):printf("Little-Endian"))
or
#include <stdio.h>
#define ENDIAN() { \
volatile unsigned long ul = 1;\
volatile unsigned char *p;\
p = (volatile unsigned char *)&ul;\
if (*p == 1)\
puts("Little endian.");\
else if (*(p+(sizeof(unsigned long)-1)) == 1)\
puts("Big endian.");\
else puts("Unknown endian.");\
}
int main(void)
{
ENDIAN();
return 0;
}
Upvotes: -4
Reputation: 787
C Code for checking whether a system is little-endian or big-indian.
int i = 7;
char* pc = (char*)(&i);
if (pc[0] == '\x7') // aliasing through char is ok
puts("This system is little-endian");
else
puts("This system is big-endian");
Upvotes: -1
Reputation: 85266
Don't forget that endianness is not the whole story - the size of char
might not be 8 bits (e.g. DSP's), two's complement negation is not guaranteed (e.g. Cray), strict alignment might be required (e.g. SPARC, also ARM springs into middle-endian when unaligned), etc, etc.
It might be a better idea to target a specific CPU architecture instead.
For example:
#if defined(__i386__) || defined(_M_IX86) || defined(_M_IX64)
#define USE_LITTLE_ENDIAN_IMPL
#endif
void my_func()
{
#ifdef USE_LITTLE_ENDIAN_IMPL
// Intel x86-optimized, LE implementation
#else
// slow but safe implementation
#endif
}
Note that this solution is also not ultra-portable unfortunately, as it depends on compiler-specific definitions (there is no standard, but here's a nice compilation of such definitions).
Upvotes: 5
Reputation: 8232
My answer is not as asked but It is really simple to find if your system is little endian or big endian?
Code:
#include<stdio.h>
int main()
{
int a = 1;
char *b;
b = (char *)&a;
if (*b)
printf("Little Endian\n");
else
printf("Big Endian\n");
}
Upvotes: -1
Reputation: 170
The 'C network library' offers functions to handle endian'ness. Namely htons(), htonl(), ntohs() and ntohl() ...where n is "network" (ie. big-endian) and h is "host" (ie. the endian'ness of the machine running the code).
These apparent 'functions' are (commonly) defined as macros [see <netinet/in.h>], so there is no runtime overhead for using them.
The following macros use these 'functions' to evaluate endian'ness.
#include <arpa/inet.h>
#define IS_BIG_ENDIAN (1 == htons(1))
#define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN)
In addition:
The only time I ever need to know the endian'ness of a system is when I write-out a variable [to a file/other] which may be read-in by another system of unknown endian'ness (for cross-platform compatability) ...In cases such as these, you may prefer to use the endian functions directly:
#include <arpa/inet.h>
#define JPEG_MAGIC (('J'<<24) | ('F'<<16) | ('I'<<8) | 'F')
// Result will be in 'host' byte-order
unsigned long jpeg_magic = JPEG_MAGIC;
// Result will be in 'network' byte-order (IE. Big-Endian/Human-Readable)
unsigned long jpeg_magic = htonl(JPEG_MAGIC);
Upvotes: 7
Reputation: 49793
You can in fact access the memory of a temporary object by using a compound literal (C99):
#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})
Which GCC will evaluate at compile time.
Upvotes: 11
Reputation: 199
I believe this is what was asked for. I only tested this on a little endian machine under msvc. Someone plese confirm on a big endian machine.
#define LITTLE_ENDIAN 0x41424344UL
#define BIG_ENDIAN 0x44434241UL
#define PDP_ENDIAN 0x42414443UL
#define ENDIAN_ORDER ('ABCD')
#if ENDIAN_ORDER==LITTLE_ENDIAN
#error "machine is little endian"
#elif ENDIAN_ORDER==BIG_ENDIAN
#error "machine is big endian"
#elif ENDIAN_ORDER==PDP_ENDIAN
#error "jeez, machine is PDP!"
#else
#error "What kind of hardware is this?!"
#endif
As a side note (compiler specific), with an aggressive compiler you can use "dead code elimination" optimization to achieve the same effect as a compile time #if
like so:
unsigned yourOwnEndianSpecific_htonl(unsigned n)
{
static unsigned long signature= 0x01020304UL;
if (1 == (unsigned char&)signature) // big endian
return n;
if (2 == (unsigned char&)signature) // the PDP style
{
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
if (4 == (unsigned char&)signature) // little endian
{
n = (n << 16) | (n >> 16);
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
// only weird machines get here
return n; // ?
}
The above relies on the fact that the compiler recognizes the constant values at compile time, entirely removes the code within if (false) { ... }
and replaces code like if (true) { foo(); }
with foo();
The worst case scenario: the compiler does not do the optimization, you still get correct code but a bit slower.
Upvotes: 19
Reputation:
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
Upvotes: 4
Reputation: 70204
If you want to only rely on the preprocessor, you have to figure out the list of predefined symbols. Preprocessor arithmetics has no concept of addressing.
GCC on Mac defines __LITTLE_ENDIAN__
or __BIG_ENDIAN__
$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1
Then, you can add more preprocessor conditional directives based on platform detection like #ifdef _WIN32
etc.
Upvotes: 20
Reputation: 92854
Try this:
#include<stdio.h>
int x=1;
#define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian")
int main()
{
TEST;
}
Upvotes: 3
Reputation: 75615
Whilst there is no portable #define or something to rely upon, platforms do provide standard functions for converting to and from your 'host' endian.
Generally, you do storage - to disk, or network - using 'network endian', which is BIG endian, and local computation using host endian (which on x86 is LITTLE endian). You use htons()
and ntohs()
and friends to convert between the two.
Upvotes: 5
Reputation: 202475
To detect endianness at run time, you have to be able to refer to memory. If you stick to standard C, declarating a variable in memory requires a statement, but returning a value requires an expression. I don't know how to do this in a single macro—this is why gcc has extensions :-)
If you're willing to have a .h file, you can define
static uint32_t endianness = 0xdeadbeef;
enum endianness { BIG, LITTLE };
#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
: *(const char *)&endianness == 0xde ? BIG \
: assert(0))
and then you can use the ENDIANNESS
macro as you will.
Upvotes: 29
Reputation: 798456
There is no standard, but on many systems including <endian.h>
will give you some defines to look for.
Upvotes: 55
Reputation: 1975
Use an inline function rather than a macro. Besides, you need to store something in memory which is a not-so-nice side effect of a macro.
You could convert it to a short macro using a static or global variable, like this:
static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
Upvotes: 6