c - 处理枚举按位大小大于 64

标签 c enums bit-manipulation

我的枚举是这样的:

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

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

谢谢。

最佳答案

根据C11 6.7.2.2枚举说明符/2(我的粗体):

The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

因此,当前拥有 N 位宽的枚举的唯一方法是,如果您的 int 类型是 N 位宽。当前,您很难找到具有比 64 位 int 值更好的实现(尽管我毫不怀疑它们即将到来)。

枚举可能比位掩码更适合连续值。如果您想要执行任意大小的位掩码,您应该考虑使用无符号整数类型的数组,最好是像 uint8_t 这样的固定大小,以简化处理。

以下例程可能是一个好的开始。首先,所需的 header 、结构和辅助数组:

#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__

关于c - 处理枚举按位大小大于 64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27226692/

相关文章:

c - 使用超出范围的声明

c - 如何删除数组中特定位置的字符?

java - 如何更改 IntelliJ 12 枚举的重新格式化行为?

c - C 语言中的位域

python - int 如何作为 bool 语句求值?

c++ - 为什么不能用 GCC 生成静态二进制文件

c - 使用函数指针的正确风格是什么?

java - 使用 ORMLite 将枚举集合存储在数据库中

powershell - ExtendedPropertyDefinition ID 是否有公共(public)枚举?

java - Java中字节数组的位移位操作