70

我如何在 C++ 中使用它?什么时候有用?
请给我一个使用位掩码的问题示例,它实际上是如何工作的。谢谢!

4

4 回答 4

123

简要地说,位掩码有助于操纵多个值的位置。这里有一个很好的例子;

位标志是一种在一个变量中存储多个不互斥的值的方法。你可能以前见过他们。每个标志都是一个位位置,可以设置为开或关。然后,您有一堆位掩码 #defined 为每个位位置,以便您可以轻松地操作它:

    #define LOG_ERRORS            1  // 2^0, bit 0
    #define LOG_WARNINGS          2  // 2^1, bit 1
    #define LOG_NOTICES           4  // 2^2, bit 2
    #define LOG_INCOMING          8  // 2^3, bit 3
    #define LOG_OUTGOING         16  // 2^4, bit 4
    #define LOG_LOOPBACK         32  // and so on...

// Only 6 flags/bits used, so a char is fine
unsigned char flags;

// initialising the flags
// note that assigning a value will clobber any other flags, so you
// should generally only use the = operator when initialising vars.
flags = LOG_ERRORS;
// sets to 1 i.e. bit 0

//initialising to multiple values with OR (|)
flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;
// sets to 1 + 2 + 8 i.e. bits 0, 1 and 3

// setting one flag on, leaving the rest untouched
// OR bitmask with the current value
flags |= LOG_INCOMING;

// testing for a flag
// AND with the bitmask before testing with ==
if ((flags & LOG_WARNINGS) == LOG_WARNINGS)
   ...

// testing for multiple flags
// as above, OR the bitmasks
if ((flags & (LOG_INCOMING | LOG_OUTGOING))
         == (LOG_INCOMING | LOG_OUTGOING))
   ...

// removing a flag, leaving the rest untouched
// AND with the inverse (NOT) of the bitmask
flags &= ~LOG_OUTGOING;

// toggling a flag, leaving the rest untouched
flags ^= LOG_LOOPBACK;



**

警告:不要使用相等运算符(即 bitflags == 位掩码)来测试是否设置了标志 - 只有在设置了该标志并且所有其他标志都未设置时,该表达式才会为真。要测试单个标志,您需要使用 & 和 == :

**

if (flags == LOG_WARNINGS) //DON'T DO THIS
   ...
if ((flags & LOG_WARNINGS) == LOG_WARNINGS) // The right way
   ...
if ((flags & (LOG_INCOMING | LOG_OUTGOING)) // Test for multiple flags set
         == (LOG_INCOMING | LOG_OUTGOING))
   ...

你也可以搜索C++ Triks

于 2013-09-03T12:12:29.987 回答
37

当您想要在单个数据值中存储(并随后提取)不同的数据时,位掩码是“有用的”。

我之前使用的一个示例应用程序是假设您将颜色 RGB 值存储在 16 位值中。所以看起来像这样的东西:

RRRR RGGG GGGB BBBB

然后,您可以使用位掩码来检索颜色分量,如下所示:

  const unsigned short redMask   = 0xF800;
  const unsigned short greenMask = 0x07E0;
  const unsigned short blueMask  = 0x001F;

  unsigned short lightGray = 0x7BEF;

  unsigned short redComponent   = (lightGray & redMask) >> 11;
  unsigned short greenComponent = (lightGray & greenMask) >> 5;
  unsigned short blueComponent =  (lightGray & blueMask);
于 2013-09-03T12:10:11.673 回答
6

假设我有 32 位 ARGB 值,每个通道 8 位。我想用另一个 alpha 值替换 alpha 分量,例如 0x45

unsigned long alpha = 0x45
unsigned long pixel = 0x12345678;
pixel = ((pixel & 0x00FFFFFF) | (alpha << 24));

掩码将前 8 位变为 0,即旧 alpha 值所在的位置。alpha 值向上移动到它将占用的最终位位置,然后将其与掩码像素值进行或运算。最终结果是 0x45345678 存储到像素中。

于 2013-09-03T12:12:36.393 回答
4

当您想在一个数字中编码多层信息时,使用位掩码。

因此(假设 unix 文件权限)如果要存储 3 级访问限制(读取、写入、执行),您可以通过检查相应位来检查每个级别。

rwx
---
110

以 2 为底的 110 转换为以 10 为底的 6。

因此,您可以轻松地检查是否允许某人读取文件,例如通过使用所需权限的权限字段来读取文件。

伪代码:

PERM_READ = 4
PERM_WRITE = 2
PERM_EXEC = 1

user_permissions = 6

if ((user_permissions & PERM_READ) == PERM_READ) then
  // this will be reached, as 6 & 4 is true
fi

您需要对数字的二进制表示和逻辑运算符有一定的了解才能理解位域。

于 2013-09-03T12:12:55.283 回答