ventana tiempo son que poner mostrar los hacer errores error ejecución dev compilación compilacion como barra aparecer c endianness

son - Determinación de endianidad en tiempo de compilación



tiempo de compilacion (10)

¿Existe una manera segura y portátil de determinar (durante el tiempo de compilación) la endianidad de la plataforma en la que se está compilando mi programa? Estoy escribiendo en C.

[EDITAR] ¡Gracias por las respuestas, decidí seguir con la solución de tiempo de ejecución!


Con C99, puede realizar el control como:

#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)

Los condicionales como if (I_AM_LITTLE) se evaluarán en tiempo de compilación y permitirán que el compilador optimice bloques enteros.

No tengo la referencia de inmediato para ver si esto es estrictamente una expresión constante en C99 (que permitiría su uso en los inicializadores para datos de duración de almacenamiento estático), pero si no, es la mejor opción.



EDIT2: Este método no funciona. La representación de la constante multibyte es específica del compilador / plataforma y no se puede usar de manera confiable. El enlace interjay dio ( http://www.ideone.com/LaKpj ) da un ejemplo donde falla. En Solaris / SPARC, el mismo compilador gcc 4.3.3 da la respuesta correcta, pero el compilador SUNStudio 12 tendrá el mismo comportamiento que el gcc 4.3.4 en x86 utilizado en ese enlace.

Entonces, podemos concluir, todavía no hay un buen uso del carácter multibyte

Encontré este nuevo método que tiene la ventaja de ser simple y compilar el tiempo.

switch(''AB'') { case 0x4142: printf("ASCII Big endian/n"); break; case 0x4241: printf("ASCII Little endian/n"); break; case 0xC1C2: printf("EBCDIC Big endian/n"); break; case 0xC2C1: printf("EBCDIC Little endian/n"); break; }

EDITAR:

Encontré incluso una forma de hacerlo en el pre-procesador:

#if ''AB'' == 0x4142 #error "ASCII Big endian/n" #elif ''AB'' == 0x4241 #error "ASCII Little endian/n" #elif ''AB'' == 0xC1C2 #error "EBCDIC Big endian/n" #elif ''AB'' == 0xC2C1 #error "EBCDIC Little endian/n" #else #error "unknown coding and endianness/n" #endif

Y antes de que alguien pregunte, las constantes de caracteres multibyte son ANSI-C (incluso C90) pero están definidas por la implementación. Esta es la primera aplicación útil que he encontrado para ellos.


Interesante lectura de la C Preguntas frecuentes :

Probablemente no puedas. Las técnicas usuales para detectar endianness involucran punteros o matrices de char, o tal vez uniones, pero la aritmética del preprocesador solo usa números enteros largos, y no hay un concepto de direccionamiento. Otra posibilidad tentadora es algo así como

#if ''ABCD'' == 0x41424344

pero esto tampoco es confiable.


Me gustaría extender las respuestas para proporcionar una función constexpr para C ++

union Mix { int sdat; char cdat[4]; }; static constexpr Mix mix { 0x1 }; constexpr bool isLittleEndian() { return mix.cdat[0] == 1; }

Como la mix es constexpr , es tiempo de compilación y se puede usar en constexpr bool isLittleEndian() . Debe ser seguro de usar.

Actualizar

Como @Cheersandhth señaló a continuación, estos parecen ser problemáticos.

La razón es que no es C ++ 11-Estándar conforme , donde el tipo de juego de palabras está prohibido. Siempre puede haber un solo miembro de la unión activo a la vez. Con un compilador estándar compatible, obtendrá un error.

Entonces, no lo use en C ++. Parece que puedes hacerlo en C sin embargo. Dejo mi respuesta con fines educativos :-) y porque la pregunta es sobre C ...


No durante el tiempo de compilación, pero quizás durante el tiempo de ejecución. Aquí hay una función de C que escribí para determinar la endianidad:

/* Returns 1 if LITTLE-ENDIAN or 0 if BIG-ENDIAN */ #include <inttypes.h> int endianness() { union { uint8_t c[4]; uint32_t i; } data; data.i = 0x12345678; return (data.c[0] == 0x78); }


Para responder la pregunta original de una verificación en tiempo de compilación , no existe una forma estandarizada de hacerlo que funcione en todos los compiladores actuales y futuros, porque ninguno de los estándares existentes de C, C ++ y POSIX definen macros para detectar endianness.

Pero, si está dispuesto a limitarse a un conjunto conocido de compiladores, puede buscar cada una de las compilaciones de esos compiladores para averiguar qué macros predefinidas (si las hay) utilizan para definir endianness. Esta página enumera varias macros que puedes buscar, así que aquí hay un código que funcionaría para ellas:

#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || / defined(__BIG_ENDIAN__) || / defined(__ARMEB__) || / defined(__THUMBEB__) || / defined(__AARCH64EB__) || / defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) // It''s a big-endian target architecture #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || / defined(__LITTLE_ENDIAN__) || / defined(__ARMEL__) || / defined(__THUMBEL__) || / defined(__AARCH64EL__) || / defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) // It''s a little-endian target architecture #else #error "I don''t know what architecture this is!" #endif

Si no puede encontrar las macros predefinidas que su compilador usa en su documentación, también puede intentar obligarlo a escupir su lista completa de macros predefinidas y adivinar de allí qué funcionará (busque cualquier cosa con ENDIAN, ORDER o el procesador). nombre de la arquitectura en él). Esta página enumera una serie de métodos para hacerlo en diferentes compiladores:

Compiler C macros C++ macros Clang/LLVM clang -dM -E -x c /dev/null clang++ -dM -E -x c++ /dev/null GNU GCC/G++ gcc -dM -E -x c /dev/null g++ -dM -E -x c++ /dev/null Hewlett-Packard C/aC++ cc -dM -E -x c /dev/null aCC -dM -E -x c++ /dev/null IBM XL C/C++ xlc -qshowmacros -E /dev/null xlc++ -qshowmacros -E /dev/null Intel ICC/ICPC icc -dM -E -x c /dev/null icpc -dM -E -x c++ /dev/null Microsoft Visual Studio (none) (none) Oracle Solaris Studio cc -xdumpmacros -E /dev/null CC -xdumpmacros -E /dev/null Portland Group PGCC/PGCPP pgcc -dM -E (none)

Finalmente, para completarlo, los compiladores de Microsoft Visual C / C ++ son los extraños y no tienen ninguno de los anteriores. Afortunadamente, han documentado sus macros predefinidas here , y puede usar la arquitectura del procesador de destino para inferir la endianidad. Si bien todos los procesadores soportados actualmente en Windows son little-endian ( _M_IX86 , _M_X64 , _M_IA64 y _M_ARM son little-endian), algunos procesadores históricamente compatibles como PowerPC ( _M_PPC ) eran big-endian. Pero, lo que es más relevante, la Xbox 360 es una máquina PowerPC de gran tamaño, por lo que si está escribiendo un encabezado de biblioteca multiplataforma, no tiene sentido buscar _M_PPC .


Que yo sepa, no, no durante el tiempo de compilación.

En tiempo de ejecución, puede hacer comprobaciones triviales, como establecer un valor de varios bytes en una cadena de bits conocida e inspeccionar los bytes que resultan. Por ejemplo, al usar una unión,

typedef union { uint32_t word; uint8_t bytes[4]; } byte_check;

o casting,

uint32_t word; uint8_t * bytes = &word;

Tenga en cuenta que para las verificaciones de endianness completamente portátiles, debe tener en cuenta los sistemas big-endian, little-endian y mixed-endian.


Una vez usé una construcción como esta:

uint16_t HI_BYTE = 0, LO_BYTE = 1; uint16_t s = 1; if(*(uint8_t *) &s == 1) { HI_BYTE = 1; LO_BYTE = 0; } pByte[HI_BYTE] = 0x10; pByte[LO_BYTE] = 0x20;

gcc con -O2 fue capaz de completar el tiempo de compilación. Esto significa que las variables HI_BYTE y LO_BYTE se reemplazaron por completo e incluso el acceso pByte fue reemplazado en el ensamblador por el equivalente de *(unit16_t *pByte) = 0x1020; .

Es el tiempo de compilación que se necesita.


Esto es para verificar el tiempo de compilación

Puede usar información del archivo de encabezado boost endian.hpp , que cubre muchas plataformas.

editar para verificar el tiempo de ejecución

bool isLittleEndian() { short int number = 0x1; char *numPtr = (char*)&number; return (numPtr[0] == 1); }

Crea un entero y lee su primer byte (byte menos significativo). Si ese byte es 1, entonces el sistema es poco endian, de lo contrario es big endian.

editar Pensando en eso

Sí, podría encontrarse con un problema potencial en algunas plataformas (no se puede pensar en ninguna) donde sizeof(char) == sizeof(short int) . Puede usar los tipos integrales de múltiples bytes de ancho fijo disponibles en <stdint.h> , o si su plataforma no lo tiene, de nuevo puede adaptar un encabezado de refuerzo para su uso: stdint.hpp