Pregunta

Estoy tratando de implementar una idea de compresión de datos que he tenido, y como me imagino ejecutándola contra un gran corpus de datos de prueba, pensé en codificarlo en C (principalmente tengo experiencia en lenguajes de programación como Ruby y tcl.)

Mirando los libros de O'Reilly 'vaca' sobre C, me doy cuenta de que no puedo simplemente indexar los bits de una simple variable de tipo 'char' o 'int' como me gustaría hacer para hacer comparaciones y operadores bit a bit.

¿Estoy en lo cierto en esta percepción?¿Es razonable para mí usar un tipo enumerado para representar un bit (y hacer una matriz de estos y escribir funciones para convertir hacia y desde char)?Si es así, ¿ese tipo y funciones ya están definidos en alguna biblioteca estándar?¿Existen otros enfoques (¿mejores?)?¿Hay algún código de ejemplo en algún lugar al que alguien pueda indicarme?

Gracias -

¿Fue útil?

Solución

Siguiendo lo que ha dicho Kyle, puedes utilizar una macro para hacer el trabajo duro por ti.

Es posible.

Para configurar el enésimo bit, use O:

x |= (1 << 5);// establece el sexto de la derecha

Para aclarar un poco, use AND:

x &= ~(1 << 5);// borra el sexto de la derecha

Para voltear un poco, use XOR:

x ^= (1 << 5);// voltea el sexto desde la derecha

O...

#define GetBit(var, bit) ((var & (1 << bit)) != 0) // Returns true / false if bit is set
#define SetBit(var, bit) (var |= (1 << bit))
#define FlipBit(var, bit) (var ^= (1 << bit))

Entonces puedes usarlo en código como:

int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
  // Do something
}

Otros consejos

Es posible.

Para configurar el enésimo bit, use O:

x |= (1 << 5); // sets the 5th-from right

Para aclarar un poco, use AND:

x &= ~(1 << 5); // clears 5th-from-right

Para voltear un poco, use XOR:

x ^= (1 << 5); // flips 5th-from-right

Para obtener el valor de un bit use shift y AND:

(x & (1 << 5)) >> 5 // gets the value (0 or 1) of the 5th-from-right

nota:el desplazamiento a la derecha 5 es para garantizar que el valor sea 0 o 1.Si solo está interesado en 0/no 0, puede arreglárselas sin el cambio.

Eche un vistazo a las respuestas a esta pregunta.

Teoría

No existe una sintaxis C para acceder o configurar el enésimo bit de un tipo de datos integrado (p. ej.un 'carbón').Sin embargo, puede acceder a los bits mediante una operación lógica AND y establecer bits mediante una operación lógica OR.

Como ejemplo, digamos que tiene una variable que contiene 1101 y desea verificar el segundo bit desde la izquierda.Simplemente realice un AND lógico con 0100:

1101
0100
---- AND
0100

Si el resultado es distinto de cero, entonces se debe haber establecido el segundo bit;de lo contrario no se configuró.

Si desea configurar el tercer bit desde la izquierda, realice un OR lógico con 0010:

1101
0010
---- OR
1111

Puede usar los operadores C && (para y) y || (para o) para realizar estas tareas.Necesitará construir usted mismo los patrones de acceso a bits (el 0100 y el 0010 en los ejemplos anteriores).El truco consiste en recordar que el bit menos significativo (LSB) cuenta con 1, el siguiente LSB cuenta con 2, luego 4, etc.Entonces, el patrón de acceso de bits para el enésimo LSB (comenzando en 0) es simplemente el valor de 2^n.La forma más sencilla de calcular esto en C es desplazar el valor binario 0001 (en este ejemplo de cuatro bits) hacia la izquierda el número requerido de lugares.Como este valor siempre es igual a 1 en cantidades enteras sin signo, esto es simplemente '1 << n'

Ejemplo

unsigned char myVal = 0x65; /* in hex; this is 01100101 in binary. */

/* Q: is the 3-rd least significant bit set (again, the LSB is the 0th bit)? */
unsigned char pattern = 1;
pattern <<= 3; /* Shift pattern left by three places.*/

if(myVal && (char)(1<<3)) {printf("Yes!\n");} /* Perform the test. */

/* Set the most significant bit. */
myVal |= (char)(1<<7);

Este ejemplo no ha sido probado, pero debería servir para ilustrar la idea general.

Para consultar el estado de un bit con un índice específico:

int index_state = variable & ( 1 << bit_index );

Para configurar el bit:

varabile |= 1 << bit_index;

Para reiniciar bit:

variable &= ~( 1 << bit_index );

Los bits individuales se pueden indexar de la siguiente manera.

Defina una estructura como esta:

struct
{
  unsigned bit0     : 1;
  unsigned bit1     : 1;
  unsigned bit2     : 1;
  unsigned bit3     : 1;
  unsigned reserved : 28;
} bitPattern;   

Ahora, si quiero saber los valores de bits individuales de una var denominada "valor", haga lo siguiente:

CopyMemory( &input, &value, sizeof(value) );

Para ver si el bit 2 es alto o bajo:

int state = bitPattern.bit2;

Espero que esto ayude.

Intente usar campos de bits.Tenga cuidado, la implementación puede variar según el compilador.

http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html

SI desea indexar un poco, puede:

bit = (char & 0xF0) >> 7;

obtiene el msb de un char.Incluso podrías omitir el turno derecho y hacer una prueba en 0.

bit = char & 0xF0;

si el bit está establecido, el resultado será > 0;

Obviamente, necesitas cambiar la máscara para obtener bits diferentes (NB:el 0xF es la máscara de bits si no está claro).Es posible definir numerosas máscaras, p.e.

#define BIT_0 0x1 // or 1 << 0
#define BIT_1 0x2 // or 1 << 1
#define BIT_2 0x4 // or 1 << 2
#define BIT_3 0x8 // or 1 << 3

etc...

Esto te da:

bit = char & BIT_1;

Puede utilizar estas definiciones en el código anterior para indexar con éxito un bit dentro de una macro o una función.

Para configurar un poco:

char |= BIT_2;

Para aclarar un poco:

char &= ~BIT_3

Para alternar un poco

char ^= BIT_4

¿Esta ayuda?

Hay un contenedor de biblioteca estándar para bits:estándar::vector.Está especializado en la biblioteca para ahorrar espacio.También hay una clase boostdynamic_bitset.

Estos le permitirán realizar operaciones en un conjunto de valores booleanos, utilizando un bit por valor de almacenamiento subyacente.

Impulsar la documentación de bits dinámicos

Para obtener la documentación STL, consulte la documentación del compilador.

Por supuesto, también se pueden direccionar manualmente los bits individuales en otros tipos integrales.Si hace eso, debe usar tipos sin signo para no obtener un comportamiento indefinido si decide hacer un desplazamiento hacia la derecha en un valor con el bit alto establecido.Sin embargo, parece que quieres los contenedores.

Para el comentarista que afirmó que esto ocupa 32 veces más espacio del necesario:boost::dynamic_bitset y vector están especializados para usar un bit por entrada, por lo que no hay una penalización de espacio, asumiendo que realmente desea más que el número de bits en un tipo primitivo.Estas clases le permiten abordar bits individuales en un contenedor grande con almacenamiento subyacente eficiente.Si solo desea (digamos) 32 bits, utilice un int.Si desea una gran cantidad de bits, puede utilizar un contenedor de biblioteca.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top