C Definición de macro para determinar big endian o little endian machine?

¿Hay una definición de macro de una línea para determinar la endianidad de la máquina? Estoy usando el siguiente código pero convertirlo a macro sería demasiado largo.

unsigned char test_endian( void ) { int test_var = 1; unsigned char test_endian* = (unsigned char*)&test_var; return (test_endian[0] == NULL); } 

Código que admite órdenes de bytes arbitrarios, listo para colocarse en un archivo llamado order32.h :

 #ifndef ORDER32_H #define ORDER32_H #include  #include  #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 

Verificaría pequeños sistemas de endian a través de

 O32_HOST_ORDER == O32_LITTLE_ENDIAN 

Si tiene un comstackdor que admita literales compuestos C99:

 #define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1}) 

o:

 #define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c) 

Sin embargo, en general, debe intentar escribir un código que no dependa de la endianidad de la plataforma de host.


Ejemplo de implementación independiente de host-endianness de 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]; } 

No existe un estándar, pero en muchos sistemas, incluido le dará algunas definiciones para buscar.

Para detectar endianness en tiempo de ejecución, debe poder referirse a la memoria. Si se apega al estándar C, declarar una variable en la memoria requiere una statement, pero devolver un valor requiere una expresión. No sé cómo hacer esto en una sola macro, esta es la razón por la cual gcc tiene extensiones 🙂

Si está dispuesto a tener un archivo .h, puede definir

 static uint32_t endianness = 0xdeadbeef; enum endianness { BIG, LITTLE }; #define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \ : *(const char *)&endianness == 0xde ? BIG \ : assert(0)) 

y luego puedes usar la macro ENDIANNESS como quieras.

Si solo desea confiar en el preprocesador, debe averiguar la lista de símbolos predefinidos. La aritmética preprocesadora no tiene un concepto de direccionamiento.

GCC en Mac define __LITTLE_ENDIAN__ o __BIG_ENDIAN__

 $ gcc -E -dM - < /dev/null |grep ENDIAN #define __LITTLE_ENDIAN__ 1 

Luego, puede agregar más directivas condicionales de preprocesador basadas en detección de plataformas como #ifdef _WIN32 etc.

Creo que esto es lo que se pidió. Solo probé esto en una pequeña máquina endian bajo msvc. Alguien puede confirmar en una gran máquina endian.

  #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 

Como nota al margen (específica del comstackdor), con un comstackdor agresivo puede usar la optimización de “eliminación de código #if ” para lograr el mismo efecto que un tiempo de comstackción #if así:

  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; // ? } 

Lo anterior se basa en el hecho de que el comstackdor reconoce los valores constantes en tiempo de comstackción, elimina por completo el código dentro de if (false) { ... } y reemplaza el código como if (true) { foo(); } if (true) { foo(); } con foo(); El peor de los casos: el comstackdor no realiza la optimización, aún obtiene el código correcto pero un poco más lento.

Si está buscando una prueba de tiempo de comstackción y está utilizando gcc, puede hacer:

 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 

Vea la documentación de gcc para más información.

De hecho, puede acceder a la memoria de un objeto temporal utilizando un literal compuesto (C99):

 #define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1}) 

Qué GCC evaluará en tiempo de comstackción.

La ‘biblioteca de red C’ ofrece funciones para manejar la endianidad. Es decir, htons (), htonl (), ntohs () y ntohl () … donde n es “red” (es decir, big-endian) y h es “host” (es decir, el endianness de la máquina que ejecuta el código).

Estas “funciones” aparentes (comúnmente) se definen como macros [ver ], por lo que no hay sobrecarga de tiempo de ejecución para usarlas.

Las siguientes macros usan estas ‘funciones’ para evaluar el endianismo.

 #include  #define IS_BIG_ENDIAN (1 == htons(1)) #define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN) 

En adición:

La única vez que necesito saber el carácter endógeno de un sistema es cuando escribo una variable [en un archivo / otro] que puede ser leída por otro sistema de identidad desconocida (para la compatibilidad multiplataforma) ) … En casos como estos, puede preferir usar las funciones endian directamente:

 #include  #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); 

Use una función en línea en lugar de una macro. Además, debe almacenar algo en la memoria, que es un efecto secundario no tan agradable de una macro.

Puede convertirlo a una macro corta usando una variable estática o global, como esta:

 static int s_endianess = 0; #define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0) 

Si bien no existe #define portátil o algo en lo que confiar, las plataformas sí ofrecen funciones estándar para la conversión hacia y desde su endian ‘host’.

En general, usted hace almacenamiento, en el disco, o en la red, usando ‘endian de la red’, que es BIG endian, y computación local usando el host endian (que en x86 es LITTLE endian). Utiliza htons() y ntohs() y amigos para convertir entre los dos.

Prueba esto:

 #include int x=1; #define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian") int main() { TEST; } 
 #include  #define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8) #define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8) 

No olvide que la endianidad no es toda la historia: el tamaño del char puede no ser de 8 bits (p. Ej., DSP), la negación del complemento de dos no está garantizada (por ejemplo, Cray), puede ser necesaria una alineación estricta (por ejemplo, SPARC; middle-endian cuando no está alineado), etc., etc.

En su lugar, podría ser una mejor idea apuntar a una architecture de CPU específica.

Por ejemplo:

 #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 } 

Tenga en cuenta que esta solución tampoco es ultraportátil, lamentablemente, ya que depende de las definiciones específicas del comstackdor (no hay un estándar, pero aquí hay una buena comstackción de tales definiciones).

Mi respuesta no es la que se le preguntó, pero ¿es realmente simple encontrar si su sistema es pequeño endian o big endian?

Código:

 #include int main() { int a = 1; char *b; b = (char *)&a; if (*b) printf("Little Endian\n"); else printf("Big Endian\n"); } 

C Código para verificar si un sistema es little-endian o 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"); 

Silencio tarde pero … Si absolutamente debe tener un código macro Y ultraportátil, detecte y configúrelo desde su entorno construido (cmake / autotools).

Aquí hay un progtwig simple para lograrlo, adecuado para la reducción:

 #if __STDC_VERSION__ < 199901L #error "Requires C99 compatibility" #endif #include  #include  const char MAGIC[4] = {0xDE, 0xAD, 0xBE, 0xEF}; int main(void) { uint32_t magical = *(const uint32_t *)MAGIC; switch(magical) { case 0xEFBEADDE: printf("little\n"); break; case 0xDEADBEEF: printf("big\n"); break; case 0xADDEEFBE: printf("pdp\n"); break; default: for(; magical; magical >>= 8) { switch(magical & 0xff) { case 0xDE: printf("3"); break; case 0xAD: printf("2"); break; case 0xBE: printf("1"); break; default: printf("0"); } } printf("\n");} return (0); } 

Macro para encontrar endiannes

 #define ENDIANNES() ((1 && 1 == 0) ? printf("Big-Endian"):printf("Little-Endian")) 

o

 #include  #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; }