Question

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 et Tcl.)

En parcourant les livres de C-Cow sur C, d’O'Reilly, je me rends compte que je ne peux pas simplement indexer les bits d’une simple variable de type "char" ou "int", car je voudrais faire des comparaisons binaires et les 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éfinis dans une bibliothèque standard déjà quelque part? 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 -

Était-ce utile?

La solution

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   à droite

     

Pour effacer un peu, utilisez AND:

     

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

     

Pour retourner un peu, utilisez XOR:

     

x ^ = (1 < < 5); // retourne le 6ème 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 un code tel que:

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

Autres conseils

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.

Consultez 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é ou de le définir (par exemple, un "caractère"). 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, supposons que vous avez une variable qui contient 1101 et que vous souhaitez 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 & amp; & amp; (pour AND) et || (pour OU) pour effectuer ces tâches. Vous devrez construire vous-même les modèles d'accès 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 modèle d’accès aux bits pour le niè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 binaire 0001 (dans cet exemple à quatre bits) vers la gauche du nombre de places requis. Comme cette valeur est toujours égale à 1 en quantités non signées de type entier, ceci est simplement '1 & Lt; & Lt; 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 );

Chaque bit peut être indexé 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 var 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 vous aidera.

Essayez d’utiliser des champs de bits. Attention, l’implémentation peut varier d’un compilateur à un autre.

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 le bon décalage et faire un test à 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 des 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 bit:

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

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

Amélioration de la documentation sur les bits dynamiques

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

Bien sûr, vous pouvez également adresser 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 faire un décalage correct sur une valeur avec le bit élevé défini. Cependant, il semble que vous souhaitiez les conteneurs.

Pour le commentateur qui affirme que cela prend 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 dans un 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top