处理枚举按位大小大于64

时间:2014-12-01 10:47:46

标签: c enums bit-manipulation

我的枚举是这样的:

enum my_enum
{
      first_val = (1LLU << 0),
      second_val = (1LLU << 1),
      ...
      last_val = first_val = (1LLU << 63)
};

但是这样我只能使用64个值,问题是如何在我的情况下和一个枚举中处理超过64个值?

谢谢。

1 个答案:

答案 0 :(得分:3)

根据C11 6.7.2.2 Enumeration specifiers /2(我的大胆):

  

定义枚举常量值的表达式应为整数常量表达式,具有可表示为int的值。

因此,如果N类型为int位宽,则当前枚举N位宽的唯一方法是。你现在很难找到一个优于64位int值的实现(尽管我不怀疑他们会来)。

枚举可能更适合连续值而不是位掩码。如果你想做任意大小的位掩码,你应该考虑一组无符号整数类型,最好是固定大小,如uint8_t,以简化你的处理。

以下例程可能是一个好的开始。首先,需要的头文件,结构和帮助器数组:

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

typedef struct {
    size_t sz;
    uint8_t data[];
} tBitSet;

uint8_t bitMask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };

接下来,分配和释放功能:

tBitSet *bitAlloc (size_t sz) {
    size_t sz8 = (sz + 7) / 8;
    tBitSet *bits =  malloc (sizeof (tBitSet) + sz8);
    if (bits != NULL) {
        bits->sz = sz;
        for (size_t pos = 0; pos < sz8; pos++)
            bits->data[pos] = 0;
    }
    return bits;
}

void bitFree (tBitSet *bits) {
    free (bits);
}

第三,设置,清除,切换和测试的功能:

void bitSet (tBitSet *bits, size_t pos) {
    if (pos < bits->sz)
        bits->data[pos / 8] |= bitMask[pos % 8];
}

void bitClear (tBitSet *bits, size_t pos) {
    if (pos < bits->sz)
        bits->data[pos / 8] &= ~bitMask[pos % 8];
}

void bitToggle (tBitSet *bits, size_t pos) {
    if (pos < bits->sz)
        bits->data[pos / 8] ^= bitMask[pos % 8];
}

int bitTest (tBitSet *bits, size_t pos) {
    if (pos < bits->sz)
        return ((bits->data[pos / 8] & bitMask[pos % 8]) == 0) ? 0 : 1;
    return 0;
}

当然,最后还有一个测试工具,用于检查我是否给了你伪造的代码: - )

#include <stdio.h>

void bitDump (char *desc, tBitSet *bits) {
    printf ("%s:", desc);
    for (size_t pos = 0; pos < (bits->sz + 7) / 8; pos++)
        printf (" $%02x", bits->data[pos]);
    putchar (':');
    for (size_t pos = 0; pos < bits->sz; pos++) {
        if ((pos % 8) == 0)
            putchar (' ');
        printf ("%d", bitTest (bits, pos));
    }
    for (size_t pos = bits->sz; (pos % 8) != 0; pos++)
        putchar ('_');
    putchar ('\n');
}

#define SZ 30

int main (void) {
    tBitSet *bits = bitAlloc (SZ);
    if (bits == NULL) {
        puts ("Could not allocate bitset");
        return 1;
    }

    bitDump ("Initial         ", bits);

    for (size_t pos = 0; pos < SZ; pos++) bitSet (bits, pos);
    bitDump ("Set all         ", bits);

    for (size_t pos = 1; pos < SZ; pos += 2) bitClear (bits, pos);
    bitDump ("Clear every two ", bits);

    for (size_t pos = 0; pos < SZ; pos++) bitToggle (bits, pos);
    bitDump ("Toggle all      ", bits);

    for (size_t pos = 1; pos < SZ; pos += 2) bitClear (bits, pos);
    bitDump ("Clear every two ", bits);

    for (size_t pos = 4; pos < SZ; pos += 5) bitSet (bits, pos);
    bitDump ("Set every five  ", bits);

    for (size_t pos = 0; pos < SZ; pos++) bitToggle (bits, pos);
    bitDump ("Toggle all      ", bits);

    for (size_t pos = 0; pos < SZ; pos += 2) bitClear (bits, pos);
    bitDump ("Clear odd       ", bits);

    for (size_t pos = 1; pos < SZ; pos += 2) bitClear (bits, pos);
    bitDump ("Clear even      ", bits);

    bitFree (bits);

    return 0;
}

其输出显示了它的工作原理:

Initial         : $00 $00 $00 $00: 00000000 00000000 00000000 000000__
Set all         : $ff $ff $ff $fc: 11111111 11111111 11111111 111111__
Clear every two : $aa $aa $aa $a8: 10101010 10101010 10101010 101010__
Toggle all      : $55 $55 $55 $54: 01010101 01010101 01010101 010101__
Clear every two : $00 $00 $00 $00: 00000000 00000000 00000000 000000__
Set every five  : $08 $42 $10 $84: 00001000 01000010 00010000 100001__
Toggle all      : $f7 $bd $ef $78: 11110111 10111101 11101111 011110__
Clear odd       : $55 $15 $45 $50: 01010101 00010101 01000101 010100__
Clear even      : $00 $00 $00 $00: 00000000 00000000 00000000 000000__