Leí que el orden de los campos de bits dentro de una estructura es específico de la plataforma. ¿Qué pasa si utilizo diferentes opciones de empaquetado específicas del compilador, esto garantizará que los datos se almacenen en el orden correcto tal como están escritos? Por ejemplo:
struct Message
{
unsigned int version : 3;
unsigned int type : 1;
unsigned int id : 5;
unsigned int data : 6;
} __attribute__ ((__packed__));
En un procesador Intel con el compilador GCC, los campos se colocaron en la memoria tal como se muestran. Message.version
fueron los primeros 3 bits en el búfer y Message.type
siguieron. Si encuentro opciones de empaquetado de estructuras equivalentes para varios compiladores, ¿será multiplataforma?
c++
c
bit-manipulation
endianness
bit
Dewald
fuente
fuente
Respuestas:
No, no será completamente portátil. Las opciones de empaquetado para estructuras son extensiones y en sí mismas no son completamente portátiles. Además de eso, C99 §6.7.2.1, párrafo 10 dice: "El orden de asignación de campos de bits dentro de una unidad (de orden superior a orden inferior o de orden inferior a orden superior) está definido por la implementación".
Incluso un solo compilador podría distribuir el campo de bits de manera diferente dependiendo del endianness de la plataforma de destino, por ejemplo.
fuente
packed
cumplir el pedido: stackoverflow.com/questions/1756811/… cómo hacer cumplir el pedido de bits: stackoverflow.com/questions/6728218/gcc-compiler-bit-orderLos campos de bits varían mucho de un compilador a otro, lo siento.
Con GCC, las máquinas Big Endian colocan primero el extremo grande de los bits y las máquinas Little Endian colocan primero el extremo pequeño de los bits.
K&R dice "Los elementos de estructuras de campo adyacente [bit-] se empaquetan en unidades de almacenamiento dependientes de la implementación en una dirección dependiente de la implementación. Cuando un campo que sigue a otro campo no encaja ... puede dividirse entre unidades o la unidad puede ser padded. Un campo sin nombre de ancho 0 fuerza este relleno ... "
Por lo tanto, si necesita un diseño binario independiente de la máquina, debe hacerlo usted mismo.
Esta última declaración también se aplica a los campos que no son de bits debido al relleno; sin embargo, todos los compiladores parecen tener alguna forma de forzar el empaquetado de bytes de una estructura, como veo que ya descubrió para GCC.
fuente
Deben evitarse los campos de bits; no son muy portátiles entre compiladores, incluso para la misma plataforma. del estándar C99 6.7.2.1/10 - "Especificadores de estructura y unión" (hay una redacción similar en el estándar C90):
No puede garantizar si un campo de bits 'abarcará' un límite int o no y no puede especificar si un campo de bits comienza en el extremo inferior del int o en el extremo superior del int (esto es independiente de si el procesador es big-endian o little-endian).
Prefiere las máscaras de bits. Utilice líneas (o incluso macros) para configurar, borrar y probar los bits.
fuente
_BIT_FIELDS_LTOH
y_BIT_FIELDS_HTOL
endianness están hablando de órdenes de bytes, no de órdenes de bits. Hoy en día , es 99% seguro que las órdenes de bits son fijas. Sin embargo, cuando se utilizan campos de bits, se debe tener en cuenta la endianidad. Vea el ejemplo a continuación.
#include <stdio.h> typedef struct tagT{ int a:4; int b:4; int c:8; int d:16; }T; int main() { char data[]={0x12,0x34,0x56,0x78}; T *t = (T*)data; printf("a =0x%x\n" ,t->a); printf("b =0x%x\n" ,t->b); printf("c =0x%x\n" ,t->c); printf("d =0x%x\n" ,t->d); return 0; } //- big endian : mips24k-linux-gcc (GCC) 4.2.3 - big endian a =0x1 b =0x2 c =0x34 d =0x5678 1 2 3 4 5 6 7 8 \_/ \_/ \_____/ \_____________/ a b c d // - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2 a =0x2 b =0x1 c =0x34 d =0x7856 7 8 5 6 3 4 1 2 \_____________/ \_____/ \_/ \_/ d c b a
fuente
La mayoría de las veces, probablemente, pero no apueste la granja, porque si se equivoca, perderá mucho.
Si realmente, realmente necesita tener información binaria idéntica, deberá crear campos de bits con máscaras de bits; por ejemplo, usa un código corto sin firmar (16 bits) para Mensaje y luego crea cosas como versionMask = 0xE000 para representar los tres bits superiores.
Existe un problema similar con la alineación dentro de las estructuras. Por ejemplo, las CPU Sparc, PowerPC y 680x0 son todas big-endian, y el valor predeterminado común para los compiladores Sparc y PowerPC es alinear los miembros de la estructura en límites de 4 bytes. Sin embargo, un compilador que usé para 680x0 solo se alineó en límites de 2 bytes, ¡y no había ninguna opción para cambiar la alineación!
Entonces, para algunas estructuras, los tamaños en Sparc y PowerPC son idénticos, pero más pequeños en 680x0, y algunos de los miembros están en diferentes desplazamientos de memoria dentro de la estructura.
Este fue un problema con un proyecto en el que trabajé, porque un proceso de servidor que se ejecutaba en Sparc consultaba a un cliente y descubría que era big-endian, y suponía que simplemente podía lanzar estructuras binarias en la red y el cliente podía hacer frente. Y eso funcionó bien en los clientes de PowerPC y se estrelló enormemente en los clientes de 680x0. No escribí el código y me tomó bastante tiempo encontrar el problema. Pero fue fácil de arreglar una vez que lo hice.
fuente
Gracias @BenVoigt por su útil comentario a partir de
Fuente de Linux hace uso de un campo de bits para que coincida con una estructura externa: /usr/include/linux/ip.h tiene el código para el primer byte de un datagrama IP
struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4; #else #error "Please fix <asm/byteorder.h>" #endif
Sin embargo, a la luz de su comentario, renuncio a intentar que esto funcione para el campo de bits multibyte frag_off .
fuente
Por supuesto, la mejor respuesta es usar una clase que lea / escriba campos de bits como una secuencia. El uso de la estructura de campo de bits C simplemente no está garantizado. Sin mencionar que se considera poco profesional / vago / estúpido usar esto en la codificación del mundo real.
fuente