web-dev-qa-db-fra.com

Tableau de bits efficace C/C++

Pouvez-vous recommander une méthode efficace/propre pour manipuler un tableau de bits de longueur arbitraire?

En ce moment, j'utilise un masque de bits normal int/char, mais ceux-ci ne sont pas très propres lorsque la longueur du tableau est supérieure à la longueur du type de données.

std vector<bool> n'est pas disponible pour moi.

32
Anycorn

boost::dynamic_bitset si la longueur n'est connue que pendant l'exécution.

std::bitset si la longueur est connue au moment de la compilation (bien que arbitraire).

22
kennytm

Étant donné que vous parlez de C et de C++, je suppose qu'une solution orientée C++ telle que boost::dynamic_bitset pourrait ne pas être applicable, et je parlerai plutôt d'une implémentation de C de bas niveau. Notez que si quelque chose comme boost::dynamic_bitset fonctionne pour vous, ou s'il existe une bibliothèque C préexistante que vous pouvez trouver, alors les utiliser peut être mieux que de rouler la vôtre.

Attention : Aucun des codes suivants n'a été testé ni même compilé, mais il devrait être très proche de ce dont vous auriez besoin.

Pour commencer, supposons que vous ayez une taille de bit fixe N. Ensuite, quelque chose comme ceci fonctionne:

typedef uint32_t Word_t;
enum { Word_SIZE = sizeof(Word_t) * 8 };

Word_t data[N / 32 + 1];

inline int bindex(int b) { return b / Word_SIZE; }
inline int boffset(int b) { return b % Word_SIZE; }

void set_bit(int b) { 
    data[bindex(b)] |= 1 << (boffset(b)); 
}
void clear_bit(int b) { 
    data[bindex(b)] &= ~(1 << (boffset(b)));
}
int get_bit(int b) { 
    return data[bindex(b)] & (1 << (boffset(b));
}
void clear_all() { /* set all elements of data to zero */ }
void set_all() { /* set all elements of data to one */ }

Comme cela est écrit, ceci est un peu rudimentaire car il n’implémente qu’un seul jeu de bits global de taille fixe. Pour résoudre ces problèmes, vous souhaitez commencer par une structure de données du type suivant:

struct bitset { Word_t *words; int nwords; };

puis écrivez des fonctions pour créer et détruire ces bitsets.

struct bitset *bitset_alloc(int nbits) {
    struct bitset *bitset = malloc(sizeof(*bitset));
    bitset->nwords = (n / Word_SIZE + 1);
    bitset->words = malloc(sizeof(*bitset->words) * bitset->nwords);
    bitset_clear(bitset);
    return bitset;
}

void bitset_free(struct bitset *bitset) {
    free(bitset->words);
    free(bitset);
}

Maintenant, il est relativement simple de modifier les fonctions précédentes pour prendre un paramètre struct bitset *. Il n’existe toujours aucun moyen de redimensionner un bitet au cours de sa durée de vie, pas plus qu’il n’existe de vérification des limites, mais il ne serait pas difficile d’ajouter à ce stade.

48
Dale Hagglund

J'ai écrit une implémentation fonctionnelle basée sur la réponse de Dale Hagglund afin de fournir un tableau de bits en C (licence BSD). 

https://github.com/noporpoise/BitArray/

S'il vous plaît laissez-moi savoir ce que vous pensez/donner des suggestions. J'espère que les personnes à la recherche d'une réponse à cette question le trouveront utile. 

12
Isaac Turner

Cette publication est plutôt ancienne, mais il existe une suite efficace de tableaux de bits en C dans ma bibliothèque ALFLB.

Pour de nombreux microcontrôleurs sans code d'opération de division matérielle, cette bibliothèque est EFFICACE car elle n'utilise pas de division, mais utilise plutôt le masquage et le transfert de bits. (Oui, je sais que certains compilateurs vont convertir une division de 8 en un quart de travail, mais cela varie d'un compilateur à l'autre.)

Il a été testé sur des baies allant jusqu'à 2 ^ 32-2 bits (environ 4 milliards de bits stockés dans 536 Mo), bien que les 2 derniers bits soient accessibles s'ils ne sont pas utilisés dans une boucle for de votre application.

Voir ci-dessous un extrait du doco. Doco is http://alfredo4570.net/src/alflb_doco/alflb.pdf , la bibliothèque est http://alfredo4570.net/src/alflb.Zip

Prendre plaisir,
Alf

//------------------------------------------------------------------
BM_DECLARE( arrayName, bitmax);
        Macro to instantiate an array to hold bitmax bits.
//------------------------------------------------------------------
UCHAR *BM_ALLOC( BM_SIZE_T bitmax); 
        mallocs an array (of unsigned char) to hold bitmax bits.
        Returns: NULL if memory could not be allocated.
//------------------------------------------------------------------
void BM_SET( UCHAR *bit_array, BM_SIZE_T bit_index);
        Sets a bit to 1.
//------------------------------------------------------------------
void BM_CLR( UCHAR *bit_array, BM_SIZE_T bit_index);
        Clears a bit to 0.
//------------------------------------------------------------------
int BM_TEST( UCHAR *bit_array, BM_SIZE_T bit_index); 
        Returns: TRUE (1) or FALSE (0) depending on a bit.
//------------------------------------------------------------------
int BM_ANY( UCHAR *bit_array, int value, BM_SIZE_T bitmax); 
        Returns: TRUE (1) if array contains the requested value (i.e. 0 or 1).
//------------------------------------------------------------------
UCHAR *BM_ALL( UCHAR *bit_array, int value, BM_SIZE_T bitmax);
        Sets or clears all elements of a bit array to your value. Typically used after a BM_ALLOC.  
        Returns: Copy of address of bit array
//------------------------------------------------------------------
void BM_ASSIGN( UCHAR *bit_array, int value, BM_SIZE_T bit_index);
        Sets or clears one element of your bit array to your value.
//------------------------------------------------------------------
BM_MAX_BYTES( int bit_max); 
        Utility macro to calculate the number of bytes to store bitmax bits.
        Returns: A number specifying the number of bytes required to hold bitmax bits.
//------------------------------------------------------------------
7
alf

Vous pouvez utiliser std :: bitset

int main() {
  const bitset<12> mask(2730ul); 
  cout << "mask =      " << mask << endl;

  bitset<12> x;

  cout << "Enter a 12-bit bitset in binary: " << flush;
  if (cin >> x) {
    cout << "x =        " << x << endl;
    cout << "As ulong:  " << x.to_ulong() << endl;
    cout << "And with mask: " << (x & mask) << endl;
    cout << "Or with mask:  " << (x | mask) << endl;
  }
}
3
Brian R. Bondy

Je sais que c'est un ancien message, mais je suis venu ici pour trouver une implémentation simple de bits C et aucune des réponses ne correspond à ce que je cherchais. J'ai donc mis en œuvre le mien en fonction de la réponse de Dale Hagglund. C'est ici :)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef uint32_t Word_t;
enum { BITS_PER_Word = 32 };
struct bitv { Word_t *words; int nwords; int nbits; };

struct bitv* bitv_alloc(int bits) {
    struct bitv *b = malloc(sizeof(struct bitv));

    if (b == NULL) {
        fprintf(stderr, "Failed to alloc bitv\n");
        exit(1);
    }

    b->nwords = (bits >> 5) + 1;
    b->nbits  = bits;
    b->words  = malloc(sizeof(*b->words) * b->nwords);

    if (b->words == NULL) {
        fprintf(stderr, "Failed to alloc bitv->words\n");
        exit(1);
    }

    memset(b->words, 0, sizeof(*b->words) * b->nwords);

    return b;
}

static inline void check_bounds(struct bitv *b, int bit) {
    if (b->nbits < bit) {
        fprintf(stderr, "Attempted to access a bit out of range\n");
        exit(1);
    }
}

void bitv_set(struct bitv *b, int bit) {
    check_bounds(b, bit);
    b->words[bit >> 5] |= 1 << (bit % BITS_PER_Word);
}

void bitv_clear(struct bitv *b, int bit) {
    check_bounds(b, bit);
    b->words[bit >> 5] &= ~(1 << (bit % BITS_PER_Word));
}

int bitv_test(struct bitv *b, int bit) {
    check_bounds(b, bit);
    return b->words[bit >> 5] & (1 << (bit % BITS_PER_Word));
}

void bitv_free(struct bitv *b) {
    if (b != NULL) {
        if (b->words != NULL) free(b->words);
        free(b);
    }
}

void bitv_dump(struct bitv *b) {
    if (b == NULL) return;

    for(int i = 0; i < b->nwords; i++) {
        Word_t w = b->words[i];

        for (int j = 0; j < BITS_PER_Word; j++) {
            printf("%d", w & 1);
            w >>= 1;
        }

        printf(" ");
    }

    printf("\n");
}

void test(struct bitv *b, int bit) {
    if (bitv_test(b, bit)) printf("Bit %d is set!\n", bit);
    else                   printf("Bit %d is not set!\n", bit);
}

int main(int argc, char *argv[]) {
    struct bitv *b = bitv_alloc(32);

    bitv_set(b, 1);
    bitv_set(b, 3);
    bitv_set(b, 5);
    bitv_set(b, 7);
    bitv_set(b, 9);
    bitv_set(b, 32);
    bitv_dump(b);
    bitv_free(b);

    return 0;
}
2
Samwhoo

J'utilise celui-ci:

//#include <bitset>
#include <iostream>
//source http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c
#define BIT_SET(a,b) ((a) |= (1<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
#define BIT_CHECK(a,b) ((a) & (1<<(b)))

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK(x,y) ((x) & (y))
1
Roel911

J'ai récemment publié BITSCAN, une bibliothèque de chaînes de bits C++ spécialement conçue pour les opérations d'analyse rapide de bits. BITSCAN est disponible ici . Il est en alpha mais reste assez bien testé depuis que je l’utilise ces dernières années pour des recherches en optimisation combinatoire (par exemple, dans BBMC , un algorithme de clique maximum exact de l’état de la technique). Une comparaison avec d'autres implémentations C++ bien connues (STL ou BOOST) peut être trouvée ici .

J'espère que tu trouves cela utile. Tous les commentaires sont les bienvenus.

1
chesslover

Dans le développement de microcontrôleurs, nous avons parfois besoin d’utiliser Tableau à 2 dimensions (matrice) avec une valeur d'élément de [0, 1] uniquement. Cette signifie que si nous utilisons 1 octet pour le type d'élément, la mémoire est considérablement gaspillée (la mémoire du micro contrôleur est très limitée). La solution proposée est que nous devrions utiliser une matrice de 1 bit (le type d'élément est 1 bit).

http://htvdanh.blogspot.com/2016/09/one-bit-matrix-for-cc-programming.html

1
Danh Hoang