C中的内存高效标志数组

时间:2011-07-27 17:26:58

标签: c arrays bit

我需要在内存中存储一​​个非常长的数组。每个数组项只是一个标志TRUE / FALSE(0/1)。我需要它非常节省内存,所以我想把它作为unsigned char区域顶部的掩码位来实现。内存中的每个char都应该给我至少8个标志。我已经实现了以下功能:

static SIZE = 8; /* 8 bits = 1 byte = 1 char */

/* creates and initializes the array for N elements */
unsigned char *new_bit_array(long n) {
    int extra = (n % SIZE) ? 1 : 0;
    size_t ms = ((n / SIZE)+extra) * sizeof(unsigned char);
    unsigned char *p = malloc(ms);
    memset(p,0xFF,ms);
    return p;
}

/* mask setter for nth bit of a char, call by function bit_array_set*/
char bit_mask_set(short nbit,short value) {    
    if (value)
        return  0xFF;
    if (nbit == 0) 
        return 0x7F;
    else if (nbit == 1)
        return 0xBF;
    else if (nbit == 2) 
        return 0xDF;
    else if (nbit == 3) 
        return 0xEF;
    else if (nbit == 4) 
        return 0xF7;
    else if (nbit == 5) 
        return 0xFB;
    else if (nbit == 6) 
        return 0xFD;
    else if (nbit == 7) 
        return 0xFE;
    return 0xFF;
}

/* mask setter for nth element of the array */
void bit_array_set(unsigned char *p,long i,int value) {
    p[i/] &= bit_mask_set(i % SIZE,value);
}

/* mask getter for nth bit of a char, call by function bit_array_get */
char bit_mask_get(short nbit) {
    if (nbit == 0) 
        return 0x80;
    else if (nbit == 1)
        return 0x40;
    else if (nbit == 2) 
        return 0x20;
    else if (nbit == 3) 
        return 0x10;
    else if (nbit == 4) 
        return 0x08;
    else if (nbit == 5) 
        return 0x04;
    else if (nbit == 6) 
        return 0x02;
    else if (nbit == 7) 
        return 0x01;
    return 0x00;
}

/* mask getter for nth element of the array */
short bit_array_get(unsigned char *p,long i) {
    return p[i/SIZE] & bit_mask_get(i % SIZE) ? 1 : 0;
}

这段代码工作正常,但我的问题是,如果C或任何广泛使用的库(即glib)中有任何内置功能可以提供相同的功能吗?

......如果有更好的方法来实现bit_mask_getbit_mask_set,那么7分支IF看起来很难看。对此代码的任何其他评论也非常受欢迎。

3 个答案:

答案 0 :(得分:8)

你可以更简单:

unsigned char flag_bitmask[MAX_FLAGS];

void setFlag( int flag) {
    flag_bitmask[flag / 8] |= (1 << (flag % 8) );
}

char isFlagSet(int flag) {
    return flag_bitmask[flag / 8] & (1 << (flag % 8) );
}

void unSetFlag(int flag) {
    flag_bitmask[flag / 8] &= ~(1 << (flag % 8) );
}

我正在使用它,你可以传递flag_bitmask数组而不是将其用作全局数据。

答案 1 :(得分:3)

您可以使用来自SIZE的宏CHAR_BIT替换<limits.h>常量,这会做同样的事情。

new_bit_array函数中,您可以用0xFF替换(unsigned char) ~0calloc不考虑char中的位数。虽然将内存初始化为零位更容易,但可以使用malloc代替bit_masK_get

return 1 << nbit; 中,您可以使用以下内容替换正文:

bit_mask_set

然后类似地将return (!!value) << nbit; 替换为:

{{1}}

这些位置与您的位置不同,但这并不重要,只要它们在彼此之间保持一致。

答案 2 :(得分:2)

您可以在结构中使用位域。您可以拥有以下结构的数组:

struct bitflags {
    unsigned char f0:1;
    unsigned char f1:1;
    unsigned char f2:1;
    unsigned char f3:1;
    unsigned char f4:1;
    unsigned char f5:1;
    unsigned char f6:1;
    unsigned char f7:1;
};

struct bitflags many_flags[9001];
many_flags[0].f0 = 1;