创建具有大量标志的bitflag变量或如何创建大的位宽数字

假设我有一个枚举,其bitflag选项大于标准数据类型中的位数:

enum flag_t { FLAG_1 = 0x1, FLAG_2 = 0x2, ... FLAG_130 = 0x400000000000000000000000000000000, }; 

由于几个原因,这是不可能的。 枚举的最大大小为128位(在我的系统中通过实验以C / gcc为单位),单个变量的最大大小为128位等。

在C中,你不能对数组执行按位运算,但在C ++中我认为你可以使用逐位运算符重载以完成循环的工作。

除了手动记住哪些标志用于大数字的工作之外,在C中有什么办法吗?

这正是比特字段的用途。

在C中,可以定义以下数据布局:

 struct flag_t { unsigned int flag1 : 1; unsigned int flag2 : 1; unsigned int flag3 : 1; (...) unsigned int flag130 : 1; (...) unsigned int flag1204 : 1; // for fun }; 

在此示例中,所有标志仅占用一位。 一个明显的优势是无限数量的标志。 另一个很大的优点是你不再局限于单位标志,你可以在中间合并一些多值标志。

但最重要的是,就单元操作而言,测试和归属会有所不同,并且可能会简化:您不再需要进行任何屏蔽,只需通过命名就可以直接访问该标志。 顺便说一下,利用这个机会给这些标志更全面的名字:)

让编译器为你的标志名称分配一个正常的从零开始的数字序列,并使用数组模拟一个宽位域,而不是试图将一个荒谬的大数字分配给枚举,这样你就可以有一个数百位的位域。无符号字符。 您可以使用unsigned char bits[128]获得1024位位域,并编写get_flag()set_flag()访问器函数来屏蔽所涉及的少量额外工作。

然而,更好的建议是再次看一下你的设计,并问自己“为什么我需要超过一百种不同的旗帜?”。 在我看来,你真正需要的是重新设计。

在这个与bitflags, Bit Manipulation和Flags相关的问题的答案中,我提供了一个使用unsigned char数组的例子,这是一个非常大的bitflags集的方法,我正在转向这个post。

此源示例提供以下内容:

  • 一组预处理器为bitflag值定义
  • 一组预处理器宏来操作位
  • 一些函数在数组上实现按位运算

一般方法如下:

  • 为标志创建一组定义,用于指定数组偏移和位模式
  • 为适当大小的unsigned char数组创建一个typedef
  • 创建一组实现按位逻辑运算的函数

答案的细节有一些改进和更多的展示

使用一组C预处理器定义来创建一组与数组一起使用的位标志。 这些bitflag定义指定unsigned char数组中的偏移量以及要操作的位。

此示例中的定义是16位值,其中高位字节包含数组偏移量,低位字节包含unsigned char数组的位标志,其偏移量位于高位字节中。 使用这种技术,您可以拥有最多256个元素,256 * 8或2,048个位标志的数组,或者从16位定义到32位long您可以拥有更多。 (在下面的注释中,位0表示字节的最低有效位,位7表示字节的最高有效位)。

 #define ITEM_FLG_01 0x0001 // array offset 0, bit 0 #define ITEM_FLG_02 0x0002 // array offset 0, bit 1 #define ITEM_FLG_03 0x0101 // array offset 1, bit 0 #define ITEM_FLG_04 0x0102 // array offset 1, bit 1 #define ITEM_FLG_05 0x0201 // array offset 2, bit 0 #define ITEM_FLG_06 0x0202 // array offset 2, bit 1 #define ITEM_FLG_07 0x0301 // array offset 3, bit 0 #define ITEM_FLG_08 0x0302 // array offset 3, bit 1 #define ITEM_FLG_10 0x0908 // array offset 9, bit 7 

接下来,您有一组宏来设置和取消设置位以及typedef以使其更容易使用。 不幸的是,使用带有C的typedef并不能为编译器提供更好的类型检查,但它确实使它更容易使用。 这些宏不会检查它们的参数,因此您可能会觉得使用常规函数更安全。

 #define SET_BIT(p,b) (*((p) + (((b) >> 8) & 0xf)) |= (b) & 0xf) #define TOG_BIT(p,b) (*((p) + (((b) >> 8) & 0xf)) ^= (b) & 0xf) #define CLR_BIT(p,b) (*((p) + (((b) >> 8) & 0xf)) &= ~ ((b) & 0xf)) #define TST_BIT(p,b) (*((p) + (((b) >> 8) & 0xf)) & ((b) & 0xf)) typedef unsigned char BitSet[10]; 

使用该基本框架的示例如下。

 BitSet uchR = { 0 }; int bValue; SET_BIT(uchR, ITEM_FLG_01); bValue = TST_BIT(uchR, ITEM_FLG_01); SET_BIT(uchR, ITEM_FLG_03); TOG_BIT(uchR, ITEM_FLG_03); TOG_BIT(uchR, ITEM_FLG_04); CLR_BIT(uchR, ITEM_FLG_05); CLR_BIT(uchR, ITEM_FLG_01); 

接下来,您可以引入一组实用程序函数来执行我们想要支持的一些按位操作。 这些按位运算类似于内置的C运算符,例如按位Or( | )或按位和( & )。 这些函数使用内置的C运算符在所有数组元素上执行指定的运算符。

这些效用函数的特定示例修改了所提供的一组位标志。 但是,如果这是一个问题,您可以修改函数以接受三个参数,一个用于操作的结果,另外两个用于操作中使用的两组bitflags。

 void AndBits(BitSet s1, const BitSet s2) { size_t nLen = sizeof(BitSet); for (; nLen > 0; nLen--) { *s1++ &= *s2++; } } void OrBits(BitSet s1, const BitSet s2) { size_t nLen = sizeof(BitSet); for (; nLen > 0; nLen--) { *s1++ |= *s2++; } } void XorBits(BitSet s1, const BitSet s2) { size_t nLen = sizeof(BitSet); for (; nLen > 0; nLen--) { *s1++ ^= *s2++; } } 

如果使用这种方法需要多个大小的bitflags类型,那么最灵活的方法是消除typedef并使用各种大小的直unsigned char数组。 此更改需要修改实用程序函数的接口,将BitSet替换为unsigned char指针和unsigned char字符串数组,其中定义了位标志变量。 与unsigned char指针一起,您还需要指定数组的长度。

您还可以考虑一种类似于文本字符串的方法, 是否在C未定义的行为中将任意数量的字符串与嵌套函数调用连接起来? 。