¿Hay alguna forma programática para detectar si estás o no en una arquitectura big-endian o little-endian? Necesito poder escribir código que se ejecute en un sistema Intel o PPC y usar exactamente el mismo código (es decir, sin compilación condicional).
c++
algorithm
endianness
Jay T
fuente
fuente
Respuestas:
No me gusta el método basado en el tipo de juego de palabras: a menudo el compilador lo advertirá. ¡Para eso son exactamente los sindicatos!
El principio es equivalente al caso tipo sugerido por otros, pero esto es más claro y, según C99, se garantiza que es correcto. gcc prefiere esto en comparación con el elenco de puntero directo.
Esto también es mucho mejor que arreglar el endianness en el momento de la compilación: para sistemas operativos que admiten arquitectura múltiple (binario gordo en Mac os x, por ejemplo), esto funcionará tanto para ppc / i386, mientras que de lo contrario es muy fácil estropear las cosas .
fuente
CHAR_BIT != 8
?Puede hacerlo estableciendo un int y enmascarando bits, pero probablemente la forma más fácil es usar las operaciones de conversión de bytes de red incorporadas (ya que el orden de bytes de red siempre es big endian).
El violín podría ser más rápido, pero de esta manera es simple, directo y bastante imposible de estropear.
fuente
BSWAP
operación.Por favor vea este artículo :
fuente
Puede usarlo
std::endian
si tiene acceso al compilador C ++ 20, como GCC 8+ o Clang 7+.Nota:
std::endian
comenzó en<type_traits>
pero se mudó a<bit>
la reunión de 2019 en Colonia. GCC 8, Clang 7, 8 y 9 lo tienen adentro<type_traits>
mientras que GCC 9+ y Clang 10+ lo tienen adentro<bit>
.fuente
Esto normalmente se realiza en tiempo de compilación (especialmente por razones de rendimiento) mediante el uso de los archivos de encabezado disponibles en el compilador o crea el tuyo propio. En Linux tiene el archivo de encabezado "/usr/include/endian.h"
fuente
Me sorprendió que nadie haya mencionado las macros que el preprocesador define por defecto. Si bien estos variarán dependiendo de su plataforma; son mucho más limpios que tener que escribir su propio cheque endian.
Por ejemplo; si miramos las macros integradas que GCC define (en una máquina X86-64):
En una máquina PPC obtengo:
(La
:| gcc -dM -E -x c -
magia imprime todas las macros integradas).fuente
echo "\n" | gcc -x c -E -dM - |& grep -i 'endian'
no devuelve nada, mientras que gcc 3.4.3 (de/usr/sfw/bin
todos modos) en Solaris tiene una definición en este sentido. He visto problemas similares en VxWorks Tornado (gcc 2.95) -vs- VxWorks Workbench (gcc 3.4.4).Ehm ... Me sorprende que nadie se haya dado cuenta de que el compilador simplemente optimizará la prueba y pondrá un resultado fijo como valor de retorno. Esto hace que todos los ejemplos de código anteriores sean efectivamente inútiles. ¡Lo único que se devolvería es la resistencia en tiempo de compilación! Y sí, probé todos los ejemplos anteriores. Aquí hay un ejemplo con MSVC 9.0 (Visual Studio 2008).
Código C puro
Desmontaje
Quizás sea posible desactivar CUALQUIER optimización de tiempo de compilación solo para esta función, pero no lo sé. De lo contrario, es posible codificarlo en el ensamblaje, aunque eso no es portátil. E incluso entonces, incluso eso podría optimizarse. Me hace pensar que necesito un ensamblador realmente malo, implementar el mismo código para todas las CPU / conjuntos de instrucciones existentes, y bueno ... no importa.
Además, alguien aquí dijo que la resistencia no cambia durante el tiempo de ejecución. INCORRECTO. Hay máquinas bi-endian por ahí. Su resistencia puede variar durante la ejecución. TAMBIÉN, no solo hay Little Endian y Big Endian, sino también otras endianidades (qué palabra).
Odio y amo la codificación al mismo tiempo ...
fuente
Declarar una variable int:
Ahora use punteros char * para varias partes y verifique qué hay en esas partes.
Dependiendo de cuál apunta al byte 0xFF ahora puede detectar endianness. Esto requiere sizeof (int)> sizeof (char), pero definitivamente es cierto para las plataformas discutidas.
fuente
Para más detalles, puede consultar este artículo del proyecto de código Conceptos básicos sobre Endianness :
fuente
La forma en C ++ ha sido usar boost , donde las comprobaciones y los moldes del preprocesador se dividen en compartimentos dentro de bibliotecas probadas a fondo.
La Biblioteca Predef (boost / predef.h) reconoce cuatro tipos diferentes de endianness .
La biblioteca endiana fue planeada para ser enviada al estándar C ++, y soporta una amplia variedad de operaciones en datos sensibles a .
Como se indicó en las respuestas anteriores, Endianness será parte de c ++ 20.
fuente
A menos que esté utilizando un marco que ha sido portado a procesadores PPC e Intel, tendrá que hacer compilaciones condicionales, ya que las plataformas PPC e Intel tienen arquitecturas de hardware, tuberías, buses, etc. completamente diferentes. Esto hace que el código de ensamblaje sea completamente diferente entre los dos.
En cuanto a encontrar endianness, haga lo siguiente:
Obtendrá tempChar para que sea 0x12 o 0x34, de donde conocerá la resistencia.
fuente
stdint.h
y useint16_t
para pruebas futuras contra cortocircuitos diferentes en otra plataforma.Haría algo como esto:
En este sentido, obtendría una función eficiente en el tiempo que solo realiza el cálculo una vez.
fuente
Como se indicó anteriormente, use trucos de unión.
Sin embargo, existen pocos problemas con los que se aconsejaron anteriormente, sobre todo porque el acceso a la memoria no alineado es notoriamente lento para la mayoría de las arquitecturas, y algunos compiladores ni siquiera reconocerán dichos predicados constantes, a menos que las palabras estén alineadas.
Debido a que la simple prueba endian es aburrida, aquí va la función (plantilla) que cambiará la entrada / salida del entero arbitrario de acuerdo con sus especificaciones, independientemente de la arquitectura del host.
Uso:
Para convertir de endian dado a host, use:
host = endian(source, endian_of_source)
Para convertir de host endian a endian dado, use:
output = endian(hostsource, endian_you_want_to_output)
El código resultante es tan rápido como escribir ensamblaje manual en clang, en gcc es un poco más lento (desenrollado &, <<, >>, | para cada byte) pero aún decente.
fuente
fuente
#define IS_BIGENDIAN() (*((char*) &((int){ 0x00ff })) == (0x00))
¡No utilices a
union
!C ++ no permite la escritura de tipos a través de
union
s!¡Leer desde un campo sindical que no fue el último campo escrito es un comportamiento indefinido !
Muchos compiladores admiten hacerlo como extensiones, pero el lenguaje no garantiza.
Vea esta respuesta para más detalles:
https://stackoverflow.com/a/11996970
Solo hay dos respuestas válidas que están garantizadas para ser portátiles.
La primera respuesta, si tiene acceso a un sistema que admite C ++ 20,
es usarlo
std::endian
desde el<type_traits>
encabezado.(Al momento de escribir, C ++ 20 aún no se ha lanzado, pero a menos que algo afecte
std::endian
la inclusión, esta será la forma preferida de probar la resistencia en tiempo de compilación desde C ++ 20 en adelante).C ++ 20 en adelante
Antes de C ++ 20, la única respuesta válida es almacenar un número entero y luego inspeccionar su primer byte a través del tipo punteo.
A diferencia del uso de
union
s, esto está expresamente permitido por el sistema de tipos de C ++.También es importante recordar que para una portabilidad óptima se
static_cast
debe usar,porque la
reinterpret_cast
implementación está definida.C ++ 11 en adelante
C ++ 11 en adelante (sin enumeración)
C ++ 98 / C ++ 03
fuente
Esta es otra solución. Similar a la solución de Andrew Hare.
fuente
no probado, pero en mi opinión, esto debería funcionar? porque será 0x01 en little endian y 0x00 en big endian?
fuente
Declarar:
Mi publicación inicial se declara incorrectamente como "tiempo de compilación". No lo es, incluso es imposible en el estándar actual de C ++. Constexpr NO significa que la función siempre realiza cómputos en tiempo de compilación. Gracias Richard Hodges por la corrección.
Tiempo de compilación, no macro, solución C ++ 11 constexpr:
fuente
También puede hacerlo a través del preprocesador utilizando algo como el archivo de encabezado boost que se puede encontrar boost endian
fuente
A menos que el encabezado endian sea solo para GCC, proporciona macros que puede usar.
fuente
__BYTE_ORDER__
,__ORDER_LITTLE_ENDIAN__
y__ORDER_BIG_ENDIAN__
?Si no desea una compilación condicional, simplemente puede escribir código independiente endian. Aquí hay un ejemplo (tomado de Rob Pike ):
Lectura de un entero almacenado en little-endian en el disco, de manera independiente endian:
El mismo código, tratando de tener en cuenta la resistencia de la máquina:
fuente
fuente
¿Qué tal esto?
fuente
Aquí hay otra versión C. Define una macro llamada
wicked_cast()
para el punteo de tipo en línea a través de literales de unión C99 y el__typeof__
operador no estándar .Si los enteros son valores de un solo byte, la endianidad no tiene sentido y se generará un error en tiempo de compilación.
fuente
Los compiladores forma de C (al menos todos los que conozco de) trabajar el orden de bits ha de ser decidido en tiempo de compilación. Incluso para procesadores biendianos (como ARM och MIPS) debe elegir endianness en tiempo de compilación. Además, el endianness se define en todos los formatos de archivo comunes para ejecutables (como ELF). Aunque es posible crear un blob binario de código biandian (¿para algún exploit de servidor ARM tal vez?), Probablemente tenga que hacerse en ensamblador.
fuente
Como señaló Coriiander, la mayoría (si no todos) de esos códigos aquí se optimizarán en el momento de la compilación, por lo que los archivos binarios generados no verificarán la "endianness" en el tiempo de ejecución.
Se ha observado que un ejecutable dado no debería ejecutarse en dos órdenes de bytes diferentes, pero no tengo idea de si ese es siempre el caso, y me parece un truco comprobar en el momento de la compilación. Entonces codifiqué esta función:
MinGW no pudo optimizar este código, a pesar de que optimiza los otros códigos aquí. Creo que es porque dejo el valor "aleatorio" que estaba alojado en la memoria de bytes más pequeña como estaba (al menos 7 de sus bits), por lo que el compilador no puede saber cuál es ese valor aleatorio y no se optimiza La función de distancia.
También he codificado la función para que la verificación solo se realice una vez y el valor de retorno se almacene para las próximas pruebas.
fuente
0x7FE
? ¿Por qué usarmalloc()
en absoluto? Eso es un desperdicio. Y_BE
es una pérdida de memoria (aunque pequeña) y una condición de carrera esperando a suceder, los beneficios de almacenar en caché el resultado dinámicamente no valen la pena. En cambio, haría algo más como esto:static const uint16_t teste = 1; int is_little_endian() { return (0x01 == ((uint8_t*)&teste)[0]); } int is_big_endian() { return (0x01 == ((uint8_t*)&teste)[1]); }
simple y efectivo, y mucho menos trabajo para realizar en tiempo de ejecución.volatile
, o#pragma
, etc.Si bien no hay una forma rápida y estándar de determinarlo, esto lo generará:
fuente
Ver Endianness - C-Level Code illustration.
fuente
Estaba revisando el libro de texto: Sistema informático: la perspectiva de un programador , y hay un problema para determinar qué endian es esto por el programa C.
Usé la función del puntero para hacer eso de la siguiente manera:
Como int ocupa 4 bytes, y char ocupa solo 1 bytes. Podríamos usar un puntero de caracteres para señalar el int con el valor 1. Por lo tanto, si la computadora es little endian, el carácter al que apunta el puntero de caracteres tiene el valor 1; de lo contrario, su valor debería ser 0.
fuente