C语言中的标志是如何工作的?

16

最近我遇到了几个C和C++中的“标志位”示例,但我并不完全理解它们是如何工作的。在查看一些源代码后,我注意到通常标志值以十六进制定义,例如以下内容:

FLAG1 = 0x00000001,
FLAG2 = 0x00000010,

我的直觉告诉我这些值正在被组合。标志是否通过将所有标志值组合成一个int来工作?如果我像这样同时使用它们FLAG1 | FLAG2,结果会是0x00000011吗?

我需要创建带有位偏移量的枚举还是可以使用升序整数,例如:

FLAG1 = 1;
FLAG2 = 2;
4个回答

40

你需要偏移位,否则就无法提取各个标志。如果你有对应于1、2、3和4的标记,并且组合值为5,那么你如何知道它是2&3还是1&4?

你也可以用以下方法进行操作,例如:

enum {
    FIRST = 1 << 0, // same as 1
    SECOND = 1 << 1, // same as 2, binary 10
    THIRD = 1 << 2, // same as 4, binary 100
    FOURTH = 1 << 3 // same as 8, binary 1000
};

然后您可以这样组合标志:

int flags = FIRST | THIRD | FOURTH;

你可以像这样提取它们:

if (flags & THIRD) { ...

11

你的第一种方法没有充分利用二进制位。在第一个例子中,你使用了十六进制表示法,它等价于:

TEXTUREFLAGS_POINTSAMPLE = 1,
TEXTUREFLAGS_TRILINEAR = 16,

在第二种方法中,看起来你只是每次加一。当你结合标记时,这种方法不起作用,因为组合值可能与另一个标记相同(例如,1 | 2 == 3)。

相反应该使用这些值:

0x00000001  // == 1
0x00000002  // == 2
0x00000004  // == 4
0x00000008  // == 8
0x00000010  // == 16
0x00000020  // == 32
0x00000040  // == 64
etc...

以下是二的幂,它们可以使用按位或进行任意组合而不会发生冲突。


好的,但如果我只执行从1到20的操作,它不起作用,对吗? 我仍然需要错开十六进制,以便它们不会互相覆盖,是吗?或者我没有理解它的工作方式。 - Justin Meiners
1
@user425756,如果您不使用二的幂次方,您将无法区分设置了1和2或3。 - Paul Tomblin
是的,这正是我所想的。 - Justin Meiners

6

像这样的标记是二进制值,所以您可以在单个字节中组合1、2、4、8、16、32、64、128,或者在int中使用更高次幂的2直到2^31。因为它们是二进制值,您可以将它们“或”在一起,例如,如果您将1、2、4“或”在一起,最终得到7。而且您可以使用“and”提取所需的位 - 因此,如果您有一个int,其中一些标志被or在一起,并且您想查看是否设置了“4”位,您可以使用if (flag & 4),如果设置了“4”位,则条件为真。


谢谢,现在更有意义了。 - Justin Meiners

5
将标志想象成一个32位(布尔值)数组。
要将其中一个位打开,需要使用1 << BitIndex进行按位或运算(其中BitIndex是从0开始的,因此为0-31)。
要关闭其中一个位,需要使用~(1 << BitIndex)进行按位与运算。
要检查其开启或关闭状态,需要使用(1 << BitIndex)进行按位与运算。
一旦你理解了数字和逻辑的按位或/与之间的区别,这些将会变得非常清晰。然后你会更加欣赏十六进制表示法!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接