c++ - ¿Cómo obtener matriz de bits en una estructura?
internals (6)
C ++ usaría std::vector<bool>
o std::bitset<N>
.
En C, para emular la semántica std::vector<bool>
, usas una estructura como esta:
struct Bits {
Word word[];
size_t word_count;
};
donde Word
es un tipo definido por la implementación que tiene el mismo ancho que el bus de datos de la CPU; wordsize
, como se usa más adelante, es igual al ancho del bus de datos.
Por ejemplo, Word
es uint32_fast_t
para uint32_fast_t
de 32 bits, uint64_fast_t
para máquinas de 64 bits; wordsize
es 32 para máquinas de 32 bits y 64 para máquinas de 64 bits.
Usas funciones / macros para establecer / borrar bits.
Para extraer un bit, use GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize)))
.
Para establecer un bit, use SET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] |= (1 << ((bit) % wordsize)))
.
Para borrar un bit, use CLEAR_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize)))
.
Para voltear un bit, use FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize)))
.
Para agregar capacidad de cambio según std::vector<bool>
, haga una función de cambio de tamaño que llame a realloc
en Bits.word
y cambie Bits.word_count
consecuencia. Los detalles exactos de esto quedan como un problema.
Lo mismo se aplica para la correcta verificación de rango de los índices de bits.
Estaba pensando (y por lo tanto estoy buscando una manera de aprender esto, y no una mejor solución ) si es posible obtener una serie de bits en una estructura.
Déjame demostrarte con un ejemplo. Imagina un código así:
#include <stdio.h>
struct A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
int main()
{
struct A a = {1, 0, 1, 1};
printf("%u/n", a.bit0);
printf("%u/n", a.bit1);
printf("%u/n", a.bit2);
printf("%u/n", a.bit3);
return 0;
}
En este código, tenemos 4 bits individuales empaquetados en una estructura. Se puede acceder a ellos individualmente, dejando el trabajo de manipulación de bits al compilador. Lo que me preguntaba es si tal cosa es posible:
#include <stdio.h>
typedef unsigned int bit:1;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{1, 0, 1, 1}};
for (i = 0; i < 4; ++i)
printf("%u/n", b.bits[i]);
return 0;
}
Intenté declarar los bits
en la struct B
como unsigned int bits[4]:1
o unsigned int bits:1[4]
o cosas similares sin éxito. Mi mejor conjetura fue typedef unsigned int bit:1;
y usar bit
como el tipo, pero todavía no funciona.
Mi pregunta es, ¿es tal cosa posible? Si es así, ¿cómo? ¿Si no, porque no? El int sin signo de 1 bit es un tipo válido, entonces, ¿por qué no debería ser capaz de obtener una matriz de él?
Una vez más, no quiero un reemplazo para esto, solo me pregunto cómo es posible tal cosa.
PD: estoy etiquetando esto como C ++, aunque el código está escrito en C, porque asumo que el método existiría en ambos idiomas. Si hay una forma específica de C ++ de hacerlo (utilizando las construcciones de lenguaje, no las bibliotecas), también me interesaría saberlo.
ACTUALIZACIÓN: Estoy completamente consciente de que puedo hacer las operaciones de bits yo mismo. Lo he hecho mil veces en el pasado. NO estoy interesado en una respuesta que diga usar una matriz / vector en lugar de hacer la manipulación de bits. Solo estoy pensando si ESTE CONSTRUCTO es posible o no, NO una alternativa.
Actualización: Respuesta para los impacientes (gracias a neagoegab):
En lugar de
typedef unsigned int bit:1;
Podría usar
typedef struct
{
unsigned int value:1;
} bit;
correctamente usando #pragma pack
En C ++ usas std::bitset<4>
. Esto utilizará un número mínimo de palabras para el almacenamiento y ocultará todo el enmascaramiento de usted. Es realmente difícil separar la biblioteca C ++ del lenguaje porque gran parte del lenguaje está implementado en la biblioteca estándar. En C no hay una forma directa de crear una matriz de bits individuales como esta, en lugar de eso, crearía un elemento de cuatro bits o realizaría la manipulación manualmente.
EDITAR:
El int sin signo de 1 bit es un tipo válido, entonces, ¿por qué no debería ser capaz de obtener una matriz de él?
En realidad, no puede usar un tipo sin signo de 1 bit en ningún otro lugar que no sea el contexto de creación de un miembro de estructura / clase. En ese momento es tan diferente de otros tipos que no se sigue automáticamente, por lo que podría crear una matriz de ellos.
Puede crear una lista de bits utilizando un puntero de estructura. Sin embargo, esto usará más de un poco de espacio por bit escrito, ya que usará un byte (para una dirección) por bit:
struct bitfield{
unsigned int bit : 1;
};
struct bitfield *bitstream;
Luego, después de esto:
bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant );
Puedes acceder a ellos así:
bitstream[bitpointer].bit=...
También puede utilizar una matriz de enteros (ints o longs) para crear una máscara de bits arbitrariamente grande. La llamada al sistema select () usa este enfoque para su tipo fd_set; cada bit corresponde al descriptor de archivo numerado (0..N). Las macros se definen: FD_CLR para borrar un bit, FD_SET para establecer un bit, FD_ISSET para probar un bit y FD_SETSIZE es el número total de bits. Las macros determinan automáticamente a qué entero en la matriz acceder y qué bit en el entero. En Unix, vea "sys / select.h"; bajo Windows, creo que está en "winsock.h". Puede utilizar la técnica FD para crear sus propias definiciones para una máscara de bits. En C ++, supongo que podría crear un objeto de máscara de bits y sobrecargar al operador [] para acceder a bits individuales.
esto es abusivo, y se basa en una extensión ... pero funcionó para mí:
struct __attribute__ ((__packed__)) A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
union U
{
struct A structVal;
int intVal;
};
int main()
{
struct A a = {1, 0, 1, 1};
union U u;
u.structVal = a;
for (int i =0 ; i<4; i++)
{
int mask = 1 << i;
printf("%d/n", (u.intVal & mask) >> i);
}
return 0;
}
NO POSIBLE - Una construcción como esa NO ES posible ( aquí ) - NO ES POSIBLE
Se podría intentar hacer esto, pero el resultado será que un bit se almacena en un byte.
#include <cstdint>
#include <iostream>
using namespace std;
#pragma pack(push, 1)
struct Bit
{
//one bit is stored in one BYTE
uint8_t a_:1;
};
#pragma pack(pop, 1)
typedef Bit bit;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{0, 0, 1, 1}};
for (int i = 0; i < 4; ++i)
cout << b.bits[i] <<endl;
cout<< sizeof(Bit) << endl;
cout<< sizeof(B) << endl;
return 0;
}
salida:
0 //bit[0] value
0 //bit[1] value
1 //bit[2] value
1 //bit[3] value
1 //sizeof(Bit), **one bit is stored in one byte!!!**
4 //sizeof(B), ** 4 bytes, each bit is stored in one BYTE**
Para acceder a bits individuales desde un byte, aquí hay un ejemplo (tenga en cuenta que el diseño de los campos de bits depende de la implementación)
#include <iostream>
#include <cstdint>
using namespace std;
#pragma pack(push, 1)
struct Byte
{
Byte(uint8_t value):
_value(value)
{
}
union
{
uint8_t _value;
struct {
uint8_t _bit0:1;
uint8_t _bit1:1;
uint8_t _bit2:1;
uint8_t _bit3:1;
uint8_t _bit4:1;
uint8_t _bit5:1;
uint8_t _bit6:1;
uint8_t _bit7:1;
};
};
};
#pragma pack(pop, 1)
int main()
{
Byte myByte(8);
cout << "Bit 0: " << (int)myByte._bit0 <<endl;
cout << "Bit 1: " << (int)myByte._bit1 <<endl;
cout << "Bit 2: " << (int)myByte._bit2 <<endl;
cout << "Bit 3: " << (int)myByte._bit3 <<endl;
cout << "Bit 4: " << (int)myByte._bit4 <<endl;
cout << "Bit 5: " << (int)myByte._bit5 <<endl;
cout << "Bit 6: " << (int)myByte._bit6 <<endl;
cout << "Bit 7: " << (int)myByte._bit7 <<endl;
if(myByte._bit3)
{
cout << "Bit 3 is on" << endl;
}
}