2008-11-11 6 views
28

Tengo un código de serialización de bajo nivel con plantilla, y necesito conocer el endianness del sistema en tiempo de compilación, obviamente (porque las plantillas se especializan en función del endianness del sistema).¿Hay alguna forma de hacer una aserción en tiempo de compilación del estilo de C++ para determinar el endianness de la máquina?

Ahora tengo un encabezado con algunas definiciones de plataforma, pero prefiero tener alguna forma de hacer aserciones sobre endianness con alguna prueba de plantilla (como un static_assert o boost_if). La razón por la cual mi código tendrá que compilarse y ejecutarse en una amplia gama de máquinas, de muchos proveedores especializados y, probablemente, de dispositivos que no existen en 2008, por lo que no puedo adivinar qué podría necesitar ese año por el camino. Y dado que la base de código tiene una vida útil esperada de aproximadamente 10 años. Entonces no puedo seguir el código para siempre.

Espero que esto aclare mi situación.

¿Alguien sabe de una prueba en tiempo de compilación que puede determinar la endianidad, sin depender de las definiciones específicas del proveedor?

Respuesta

18

Si utiliza autoconf, puede utilizar la macro AC_C_BIGENDIAN, que está bastante garantizado para trabajar (ajuste de la WORDS_BIGENDIAN definen por defecto)

alternativamente, podría intentar algo como lo siguiente (tomado de autoconf) para obtener una prueba de que probablemente se ha optimizado de distancia (GCC, por lo menos, elimina la otra rama)

int is_big_endian() 
{ 
    union { 
     long int l; 
     char c[sizeof (long int)]; 
    } u; 

    u.l = 1; 

    if (u.c[sizeof(long int)-1] == 1) 
    { 
     return 1; 
    } 
    else 
     return 0; 
} 
+2

Gracias, eso es un buen truco. Y creo que puedo aplicarlo con un poco de reingeniería. no estoy seguro todavía, pero es una buena pista. –

5

Hmm, esa es una pregunta interesante. Mi apuesta es que esto no es posible. Creo que debe seguir usando macros, y vaya con BOOST_STATIC_ASSERT(!BIG_ENDIAN);, o static_assert en C++ 0x. La razón por la que creo que esto es porque endian'nes es una propiedad si su entorno de ejecución. Sin embargo, static_assert se considera en tiempo de compilación.

Le sugiero que busque en el código del nuevo GNU gold ELF linker. Ian Lance Taylor, su autor, usó plantillas para seleccionar el endianness correcto en tiempo de compilación, para asegurar un rendimiento óptimo en tiempo de ejecución. Él ejemplifica explícitamente todos los posibles endians, de modo que todavía tiene una compilación separada (no todas las plantillas en los encabezados) de la definición y declaración de la plantilla. Su código es excelente.

+0

Sí no hemos sido capaces de averiguarlo yo mismo, y como usted dice que podría incluso no ser posible . Pero he visto lo imposible antes para otras situaciones ... así que tal vez, tal vez alguien pueda venir con una gran idea aquí :) –

+0

¿Por qué no puede funcionar esto: '#define IS_LITTLE_ENDIAN char (0x00ff)'. Esta solución está un poco inspirada por la respuesta de @ MichaelBurr. Funciona bien con plantillas también, [demo] (http://ideone.com/JAS7mO). Supongamos 'uint8_t' en lugar de' char' para ser precisos. – iammilind

+1

@iamm No creo que sea posible construir patrones de bit en C o C++. Está construyendo el valor 255 y luego lo convierte en char. Incluso si C le permitió especificar una representación de bits, entonces aún debe convencer al compilador de que interprete ese patrón de bits como contenido de la memoria y lo cargue en un registro en lugar de tenerlo como un valor inmediato. Para registro exclusivo como truncamiento y extensión cero, endianness es irrelevante IIRC. –

18

No hay forma portátil de hacerlo en tiempo de compilación, su mejor opción es probablemente utilizar el Boostendian macros o emular los métodos que utilizan.

+0

Gracias por el enlace al encabezado. Es una buena referencia. Y similar a lo que tengo. –

Cuestiones relacionadas