indexation au niveau du bit en C?

J’essaie de mettre en œuvre une idée de compression de données que j’ai eue et, puisque j’imagine la faire fonctionner avec un grand corpus de données de test, j’avais pensé la coder en C (j’ai surtout de l’expérience dans les langages de script comme Ruby Tcl.)

En parcourant les livres de C-Cow sur C, O’Reilly, je me rends compte que je ne peux pas simplement indexer les bits d’une simple variable de type “char” ou “int”, comme j’aimerais faire des comparaisons au niveau des bits et des opérateurs.

Suis-je correct dans cette perception? Est-il raisonnable pour moi d’utiliser un type énuméré pour représenter un bit (et en faire un tableau, et écrire des fonctions pour convertir vers et depuis char)? Si tel est le cas, un tel type et de telles fonctions sont-ils déjà définis dans une bibliothèque standard? Existe-t-il d’autres approches (meilleures?)? Y a-t-il un exemple de code quelque part vers lequel quelqu’un pourrait m’indiquer?

Merci –

Pour faire suite à ce que Kyle a dit, vous pouvez utiliser une macro pour effectuer le travail difficile pour vous.

C’est possible.

Pour définir le nième bit, utilisez OU:

x | = (1 << 5); // définit le 6ème à partir de la droite

Pour effacer un peu, utilisez AND:

x & = ~ (1 << 5); // efface le 6ème de la droite

Pour retourner un peu, utilisez XOR:

x ^ = (1 << 5); // retourne la 6ème à partir de la droite

Ou…

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

Ensuite, vous pouvez l’utiliser dans le code suivant:

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

C’est possible.

Pour définir le nième bit, utilisez OU:

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

Pour effacer un peu, utilisez AND:

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

Pour retourner un peu, utilisez XOR:

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

Pour obtenir la valeur d'un bit, utilisez shift et AND:

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

remarque: le décalage à droite 5 permet de s'assurer que la valeur est 0 ou 1. Si vous êtes simplement intéressé par 0 / pas 0, vous pouvez vous en tirer sans le décalage.

Regardez les réponses à cette question .

Théorie

Il n’existe pas de syntaxe C permettant d’accéder au nième bit d’un type de données intégré (par exemple, un «caractère») ou de le définir. Cependant, vous pouvez accéder aux bits à l’aide d’une opération AND logique et définir des bits à l’aide d’une opération OR logique.

Par exemple, disons que vous avez une variable qui contient 1101 et que vous voulez vérifier le deuxième bit à partir de la gauche. Effectuez simplement un ET logique avec 0100:

 1101 0100 ---- AND 0100 

Si le résultat est différent de zéro, alors le deuxième bit doit avoir été activé; sinon ce n’était pas réglé.

Si vous souhaitez définir le troisième bit à partir de la gauche, effectuez un OU logique avec 0010:

 1101 0010 ---- OR 1111 

Vous pouvez utiliser les opérateurs C && (pour AND) et || (pour OU) pour effectuer ces tâches. Vous devrez construire vous-même les modèles d’access aux bits (0100 et 0010 dans les exemples ci-dessus). Le truc est de se rappeler que le bit le moins significatif (LSB) compte 1, le LSB suivant en compte 2, puis 4, etc. Ainsi, le motif d’access aux bits pour le n-ième LSB (à partir de 0) est simplement la valeur 2 ^ n. Le moyen le plus simple de calculer cela en C consiste à décaler la valeur binary 0001 (dans cet exemple à quatre bits) vers la gauche du nombre de places requirejs. Comme cette valeur est toujours égale à 1 en quantités non signées, il s’agit juste de «1 << n»

Exemple

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

Cet exemple n'a pas été testé, mais devrait servir à illustrer l'idée générale.

Pour interroger l’état du bit avec un index spécifique:

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

Pour définir le bit:

 varabile |= 1 << bit_index; 

Pour redémarrer le bit:

 variable &= ~( 1 << bit_index ); 

Les bits individuels peuvent être indexés comme suit.

Définissez une structure comme celle-ci:

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

Maintenant, si je veux connaître les valeurs de bit individuelles d’une variable nommée “valeur”, procédez comme suit:

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

Pour voir si le bit 2 est haut ou bas:

 int state = bitPattern.bit2; 

J’espère que cela t’aides.

Essayez d’utiliser des champs de bits. Attention, l’implémentation peut varier selon le compilateur.

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

SI vous voulez indexer un peu, vous pouvez:

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

obtient le msb d’un caractère. Vous pouvez même laisser de côté le bon quart de travail et faire un test sur 0.

 bit = char & 0xF0; 

si le bit est défini, le résultat sera> 0;

évidemment, vous devez changer le masque pour obtenir différents bits (NB: le 0xF est le masque de bits s’il n’est pas clair). Il est possible de définir de nombreux masques, par exemple

 #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...

Cela vous donne:

 bit = char & BIT_1; 

Vous pouvez utiliser ces définitions dans le code ci-dessus pour indexer avec succès un bit dans une macro ou une fonction.

Pour définir un peu:

 char |= BIT_2; 

Pour effacer un peu:

 char &= ~BIT_3 

Pour basculer un peu

 char ^= BIT_4 

Cette aide?

Il existe un conteneur de bibliothèque standard pour bits: std :: vector. Il est spécialisé dans la bibliothèque pour gagner de la place. Il existe également une classe boost_bitset dynamic.

Cela vous permettra d’effectuer des opérations sur un ensemble de valeurs booléennes, en utilisant un bit par valeur de stockage sous-jacent.

Boostez la documentation de bitset dynamic

Pour la documentation STL, consultez la documentation de votre compilateur.

Bien entendu, vous pouvez également traiter manuellement les bits individuels d’autres types d’intégraux. Si vous faites cela, vous devez utiliser des types non signés afin d’éviter tout comportement indéfini si vous décidez de décaler correctement une valeur avec le bit élevé défini. Cependant, on dirait que vous voulez les conteneurs.

Le commentateur qui a affirmé que cela prenait 32 fois plus d’espace que nécessaire: boost :: dynamic_bitset et vector sont spécialisés pour utiliser un bit par entrée. Il n’y a donc pas de pénalité d’espace, en supposant que vous souhaitiez réellement plus que le nombre de bits d’un fichier. type primitif. Ces classes vous permettent d’adresser des bits individuels dans un grand conteneur avec un stockage sous-jacent efficace. Si vous voulez simplement (par exemple) 32 bits, utilisez un int. Si vous voulez un grand nombre de bits, vous pouvez utiliser un conteneur de bibliothèque.