在这个与 bitflags、 Bit Manipulation 和 Flags相关的问题的回答中,我提供了一个使用数组的示例,该unsigned char
数组是一种处理非常大的 bitflag 集的方法,我将在此发布。
此源示例提供以下内容:
- 一组预处理器为 bitflag 值定义
- 一组预处理器宏来操作位
- 几个函数来实现对数组的按位运算
对此的一般方法如下:
- 为指定数组偏移量和位模式的标志创建一组定义
unsigned char
为适当大小的数组创建 typedef
- 创建一组实现按位逻辑运算的函数
答案中的细节有一些改进和更多的说明
使用一组 C 预处理器定义来创建一组要与数组一起使用的位标志。这些位标志定义了指定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
接下来,您有一组宏来设置和取消设置位以及 atypedef
以使其更易于使用。不幸的是typedef
,在 C 中使用 a 并不能为您提供更好的编译器类型检查,但它确实使它更易于使用。这些宏不检查它们的参数,因此您可能会觉得使用常规函数更安全。
#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 运算符,例如按位或 ( |
) 或按位与 ( &
)。这些函数使用内置的 C 运算符对所有数组元素执行指定的运算符。
实用功能的这些特定示例修改了所提供的一组位标志。但是,如果这是一个问题,您可以修改函数以接受三个参数,一个用于操作的结果,另外两个用于在操作中使用的两组位标志。
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++;
}
}
如果您使用这种方法需要多个位标志类型的大小,那么最灵活的方法可以消除typedef
并只使用unsigned char
各种大小的直接数组。此更改将需要修改实用程序函数的接口,替换为定义位标志变量BitSet
的unsigned char
指针和unsigned char
数组。除了unsigned char
指针,您还需要指定数组的长度。
您还可以考虑一种类似于在 C 未定义行为中将任意数量的字符串与嵌套函数调用连接起来的文本字符串所做的方法?.