Domanda

Sto cercando di implementare un'idea di compressione dei dati che ho avuto, e poiché sto immaginando di eseguirla su un ampio corpus di dati di test, ho pensato di codificarla in C (ho principalmente esperienza in linguaggi di scripting come Ruby e Tcl.)

Guardando i libri "cow" di O'Reilly su C, mi rendo conto che non posso semplicemente indicizzare i bit di una semplice variabile di tipo "char" o "int" come mi piacerebbe fare confronti e operatori bit a bit.

Ho ragione in questa percezione?È ragionevole per me utilizzare un tipo enumerato per rappresentare un bit (e creare un array di questi e scrivere funzioni da convertire da e verso caratteri)?In tal caso, tale tipo e funzioni sono già definiti in una libreria standard da qualche parte?Esistono altri approcci (migliori?)?C'è qualche codice di esempio da qualche parte a cui qualcuno potrebbe indicarmi?

Grazie -

È stato utile?

Soluzione

Seguendo ciò che ha detto Kyle, puoi utilizzare una macro per svolgere il lavoro duro per te.

È possibile.

Per impostare l'n-esimo bit, utilizzare OR:

x |= (1 << 5);// imposta il 6 ° a destra

Per cancellare un po', usa AND:

x &= ~(1 << 5);// cancella il 6 ° posto

Per capovolgere un po', usa XOR:

x^= (1 << 5);// capovolge la sesta da destra

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))

Quindi puoi usarlo in un codice come:

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

Altri suggerimenti

È possibile.

Per impostare l'n-esimo bit, utilizzare OR:

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

Per cancellare un po', usa AND:

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

Per capovolgere un po', usa XOR:

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

Per ottenere il valore di un bit utilizzare Shift e AND:

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

Nota:lo spostamento a destra di 5 serve per garantire che il valore sia 0 o 1.Se ti interessa solo 0/non 0, puoi farcela senza lo spostamento.

Dai un'occhiata alle risposte a questa domanda.

Teoria

Non esiste una sintassi C per accedere o impostare l'n-esimo bit di un tipo di dati integrato (ad es.un "carattere").Tuttavia, è possibile accedere ai bit utilizzando un'operazione AND logica e impostare i bit utilizzando un'operazione OR logica.

Ad esempio, supponiamo di avere una variabile che contiene 1101 e di voler controllare il 2° bit da sinistra.Esegui semplicemente un AND logico con 0100:

1101
0100
---- AND
0100

Se il risultato è diverso da zero, allora deve essere stato impostato il 2° bit;altrimenti non è stato impostato.

Se vuoi impostare il 3° bit da sinistra, esegui un OR logico con 0010:

1101
0010
---- OR
1111

È possibile utilizzare gli operatori C && (per e) e || (per o) per svolgere questi compiti.Dovrai costruire tu stesso i modelli di accesso ai bit (0100 e 0010 negli esempi precedenti).Il trucco è ricordare che il bit meno significativo (LSB) conta 1, il successivo LSB conta 2, poi 4 ecc.Pertanto, il modello di accesso al bit per l'n-esimo LSB (a partire da 0) è semplicemente il valore di 2^n.Il modo più semplice per calcolarlo in C è spostare il valore binario 0001 (in questo esempio a quattro bit) a sinistra del numero di posizioni richiesto.Poiché questo valore è sempre uguale a 1 in quantità simili a numeri interi senza segno, questo è solo '1 << n'

Esempio

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);

Questo esempio non è stato testato, ma dovrebbe servire a illustrare l'idea generale.

Per interrogare lo stato del bit con un indice specifico:

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

Per impostare il bit:

varabile |= 1 << bit_index;

Per riavviare il bit:

variable &= ~( 1 << bit_index );

I singoli bit possono essere indicizzati come segue.

Definire una struttura come questa:

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

Ora, se voglio conoscere i singoli valori dei bit di una var denominata "value", procedi come segue:

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

Per vedere se il bit 2 è alto o basso:

int state = bitPattern.bit2;

Spero che questo ti aiuti.

Prova a utilizzare i bitfield.Fare attenzione che l'implementazione possa variare in base al compilatore.

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

SE vuoi indicizzare un po' potresti:

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

ottiene il msb di un carattere.Potresti anche tralasciare lo spostamento a destra e fare un test su 0.

bit = char & 0xF0;

se il bit è impostato il risultato sarà > 0;

ovviamente è necessario cambiare la maschera per ottenere bit diversi (NB:lo 0xF è la maschera di bit se non è chiara).È possibile definire numerose maschere, ad es.

#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

eccetera...

Questo ti dà:

bit = char & BIT_1;

È possibile utilizzare queste definizioni nel codice precedente per indicizzare con successo un bit all'interno di una macro o di una funzione.

Per impostare un po':

char |= BIT_2;

Per chiarire un po':

char &= ~BIT_3

Per cambiare un po'

char ^= BIT_4

Questo aiuto?

Esiste un contenitore di libreria standard per i bit:std::vettore.È specializzato nella biblioteca per essere efficiente in termini di spazio.C'è anche una classe boost Dynamic_bitset.

Questi ti consentiranno di eseguire operazioni su un insieme di valori booleani, utilizzando un bit per valore della memoria sottostante.

Potenzia la documentazione dinamica del bitset

Per la documentazione STL, consulta la documentazione del compilatore.

Naturalmente è possibile indirizzare manualmente i singoli bit anche in altri tipi integrali.Se lo fai, dovresti usare tipi senza segno in modo da non ottenere un comportamento indefinito se decidi di fare uno spostamento a destra su un valore con il bit alto impostato.Tuttavia, sembra che tu voglia i contenitori.

Al commentatore che ha affermato che ciò richiede 32 volte più spazio del necessario:boost::dynamic_bitset e vector sono specializzati per utilizzare un bit per voce, quindi non c'è una penalità di spazio, presupponendo che tu voglia effettivamente più del numero di bit in un tipo primitivo.Queste classi consentono di indirizzare singoli bit in un contenitore di grandi dimensioni con un'efficiente archiviazione sottostante.Se vuoi solo (diciamo) 32 bit, usa un int.Se desideri un numero elevato di bit, puoi utilizzare un contenitore di libreria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top