C/C++ efficient bit array

前端 未结 10 801
清酒与你
清酒与你 2020-11-29 02:15

Can you recommend efficient/clean way to manipulate arbitrary length bit array?

Right now I am using regular int/char bitmask, but those are not very clean when arra

相关标签:
10条回答
  • 2020-11-29 02:26

    boost::dynamic_bitset if the length is only known in run time.

    std::bitset if the length is known in compile time (although arbitrary).

    0 讨论(0)
  • 2020-11-29 02:27

    In micro controller development, some times we need to use 2-dimentional array (matrix) with element value of [0, 1] only. That means if we use 1 byte for element type, it wastes the memory greatly (memory of micro controller is very limited). The proposed solution is that we should use 1 bit matrix (element type is 1 bit).

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

    0 讨论(0)
  • 2020-11-29 02:28

    I have recently released BITSCAN, a C++ bit string library which is specifically oriented towards fast bit scanning operations. BITSCAN is available here. It is in alpha but still pretty well tested since I have used it in recent years for research in combinatorial optimization (e.g. in BBMC, a state of the art exact maximum clique algorithm). A comparison with other well known C++ implementations (STL or BOOST) may be found here.

    I hope you find it useful. Any feedback is welcome.

    0 讨论(0)
  • 2020-11-29 02:29

    I know it's an old post but I came here to find a simple C bitset implementation and none of the answers quite matched what I was looking for, so I implemented my own based on Dale Hagglund's answer. Here it is :)

    #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;
    }
    
    0 讨论(0)
  • 2020-11-29 02:32

    I use this one:

    //#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))
    
    0 讨论(0)
  • 2020-11-29 02:33

    Since you mention C as well as C++, I'll assume that a C++-oriented solution like boost::dynamic_bitset might not be applicable, and talk about a low-level C implementation instead. Note that if something like boost::dynamic_bitset works for you, or there's a pre-existing C library you can find, then using them can be better than rolling your own.

    Warning: None of the following code has been tested or even compiled, but it should be very close to what you'd need.

    To start, assume you have a fixed bitset size N. Then something like the following works:

    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 */ }
    

    As written, this is a bit crude since it implements only a single global bitset with a fixed size. To address these problems, you want to start with a data struture something like the following:

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

    and then write functions to create and destroy these 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);
    }
    

    Now, it's relatively straightforward to modify the previous functions to take a struct bitset * parameter. There's still no way to re-size a bitset during its lifetime, nor is there any bounds checking, but neither would be hard to add at this point.

    0 讨论(0)
提交回复
热议问题