He definido esta estructura:
typedef struct
{
char A:3;
char B:3;
char C:3;
char D:3;
char E:3;
} col;
El sizeof(col)
me da la salida de 3, pero no debería ser 2? Si comento solo un elemento, el sizeof
es 2. No entiendo por qué: cinco elementos de 3 bits son iguales a 15 bits, y eso es menos de 2 bytes.
¿Existe un "tamaño interno" en la definición de una estructura como ésta? Solo necesito una aclaración, porque de mi noción del idioma hasta ahora, esperaba un tamaño de 2 bytes, no 3.
signed char
ounsigned char
, no puede decir sin mirar la documentación si el compilador tratará 'llano'char
en un campo de bits como firmado o sin firmar, y la decisión podría (en teoría) ser diferente de la decisión sobre si 'plain'char
está firmado o sin firmar cuando se usa fuera de un campo de bits._Bool
,signed int
,unsigned int
, o algún otro tipo definido por la implementación.char
Por lo tanto, el uso se incluye en la categoría "otro tipo definido por la implementación".Respuestas:
Debido a que está utilizando
char
como tipo subyacente para sus campos, el compilador intenta agrupar bits por bytes y, dado que no puede poner más de ocho bits en cada byte, solo puede almacenar dos campos por byte.La suma total de bits que usa su estructura es 15, por lo que el tamaño ideal para ajustar esa cantidad de datos sería a
short
.El código anterior (para una plataforma de 64 bits como la mía) de hecho dará
2
como resultado la segunda estructura. Para cualquier cosa mayor que ashort
, la estructura no llenará más de un elemento del tipo usado, por lo que, para esa misma plataforma, la estructura terminará con un tamaño de cuatro paraint
, ocho paralong
, etc.fuente
char
yshort
?char
no estén firmadas…Debido a que no puede tener un campo de paquete de bits que se extienda a través del límite de alineación mínimo (que es de 1 byte), probablemente se empaquetarán como
(los órdenes de campo / relleno dentro del mismo byte no son intencionales, es solo para darle una idea, ya que el compilador podría establecerlos como prefiera)
fuente
Los primeros dos campos de bits encajan en un solo
char
. El tercero no puede encajar en esochar
y necesita uno nuevo. 3 + 3 + 3 = 9 que no encaja en un carácter de 8 bits.Entonces, el primer par toma a
char
, el segundo par toma achar
, y el último campo de bits obtiene un tercerochar
.fuente
La mayoría de los compiladores le permiten controlar el relleno, por ejemplo
#pragma
, usando s . Aquí hay un ejemplo con GCC 4.8.1:Tenga en cuenta que el comportamiento predeterminado del compilador existe por una razón y probablemente le dará un mejor rendimiento.
fuente
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:
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 unchar
campo propio). Si todas laschar
declaraciones se hubieran reemplazado porshort
, entonces habría dos campos de tiposhort
, 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 yunsigned 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:
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.
fuente