A pesar de que el estándar ANSI C especifica muy poco sobre cómo se empaquetan los campos de bits para ofrecer una ventaja significativa sobre "los compiladores pueden empaquetar campos de bits como mejor les parezca", no obstante, en muchos casos prohíbe a los compiladores empaquetar cosas de la manera más eficiente.
En particular, si una estructura contiene campos de bits, se requiere que un compilador la almacene como una estructura que contenga uno o más campos anónimos de algún tipo de almacenamiento "normal" y luego subdividir lógicamente cada uno de esos campos en sus partes constituyentes del campo de bits. Así, dado:
unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;
Si unsigned char
es de 8 bits, el compilador deberá asignar cuatro campos de ese tipo y asignar dos campos de bits a todos menos uno (que estaría en un char
campo propio). Si todas las char
declaraciones se hubieran reemplazado por short
, entonces habría dos campos de tipo short
, uno de los cuales contendría cinco campos de bits y el otro contendría los dos restantes.
En un procesador sin restricciones de alineación, los datos se podrían distribuir de manera más eficiente utilizando unsigned short
para los primeros cinco campos y unsigned char
para los dos últimos, almacenando siete campos de tres bits en tres bytes. Si bien debería ser posible almacenar ocho campos de tres bits en tres bytes, un compilador solo podría permitirlo si existiera un tipo numérico de tres bytes que pudiera usarse como el tipo de "campo externo".
Personalmente, considero que los campos de bits definidos son básicamente inútiles. Si el código necesita trabajar con datos empaquetados en binarios, debe definir explícitamente las ubicaciones de almacenamiento de los tipos reales y luego usar macros o algún otro medio similar para acceder a los bits de los mismos. Sería útil si C admitiera una sintaxis como:
unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;
Tal sintaxis, si se permite, haría posible que el código use campos de bits de manera portátil, sin tener en cuenta el tamaño de las palabras o el orden de los bytes (foo0 estaría en los tres bits menos significativos de f1, pero esos podrían almacenarse en el dirección más baja o más alta). Sin embargo, a falta de tal característica, las macros son probablemente la única forma portátil de operar con tales cosas.