C++
Campos de bits
Buscar..
Introducción
Los campos de bits empaquetan las estructuras C y C ++ para reducir el tamaño. Esto parece indoloro: especifique el número de bits para los miembros, y el compilador hace el trabajo de mezclar bits. La restricción es la incapacidad de tomar la dirección de un miembro de campo de bit, ya que se almacena de forma combinada. sizeof()
también está deshabilitado.
El costo de los campos de bits es un acceso más lento, ya que la memoria debe recuperarse y las operaciones a nivel de bits deben aplicarse para extraer o modificar los valores de los miembros. Estas operaciones también se agregan al tamaño ejecutable.
Observaciones
¿Qué tan caras son las operaciones bitwise? Supongamos una estructura de campo no bit simple:
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
En algún código posterior:
my_var.y = 5;
Si sizeof (unsigned) == 4
, entonces x se almacena al inicio de la estructura, y se almacena y 4 bytes. El código de ensamblaje generado puede parecerse a:
loada register1,#myvar ; get the address of the structure
storei register1[4],#0x05 ; put the value '5' at offset 4, e.g., set y=5
Esto es sencillo porque x no está mezclado con y. Pero imagina redefinir la estructura con campos de bits:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
Tanto a x
como a y
se les asignarán 4 bits, compartiendo un solo byte. Por lo tanto, la estructura ocupa 1 byte, en lugar de 8. Considere el ensamblaje para establecer y
ahora, asumiendo que termina en el mordisco superior:
loada register1,#myvar ; get the address of the structure
loadb register2,register1[0] ; get the byte from memory
andb register2,#0x0f ; zero out y in the byte, leaving x alone
orb register2,#0x50 ; put the 5 into the 'y' portion of the byte
stb register1[0],register2 ; put the modified byte back into memory
Esto puede ser una buena compensación si tenemos miles o millones de estas estructuras, y ayuda a mantener la memoria en la memoria caché o evita el intercambio, o podría inflar el ejecutable para empeorar estos problemas y demorar el procesamiento. Como con todas las cosas, usa el buen juicio.
Uso del controlador de dispositivo: evite los campos de bits como una estrategia de implementación inteligente para los controladores de dispositivo. Los diseños de almacenamiento de campo de bits no son necesariamente coherentes entre los compiladores, por lo que tales implementaciones no son portátiles. La lectura-modificación-escritura para establecer valores puede no hacer lo que los dispositivos esperan, causando comportamientos inesperados.
Declaración y uso
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
Aquí, cada uno de estos dos campos ocupará 1 bit en la memoria. Se especifica mediante : 1
expresión después de los nombres de las variables. El tipo de base del campo de bits podría ser cualquier tipo integral (int de 8 bits a int de 64 bits). Se recomienda usar el tipo unsigned
, de lo contrario pueden surgir sorpresas.
Si se requieren más bits, reemplace "1" con la cantidad de bits requeridos. Por ejemplo:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
Toda la estructura está utilizando tan solo 22 bits, y con la configuración normal del compilador, sizeof
esta estructura sería de 4 bytes.
El uso es bastante simple. Solo declara la variable, y úsala como una estructura ordinaria.
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
std::cout << "Year:" << d.Year << std::endl <<
"Month:" << d.Month << std::endl <<
"Day:" << d.Day << std::endl;