如何使用位掩码

How can I use a bitmask?

本文关键字:掩码 何使用      更新时间:2023-10-16

如何在C++中使用它?什么时候使用有用?

使用位掩码来查看其实际工作方式的问题示例是什么?

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

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

    #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
// it should generally only use the = operator when initialising variables.
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;
**

警告:不要使用相等运算符(即位标志==位掩码)用于测试是否设置了标志-只有在该标志已设置,而所有其他标志都未设置。测试单个标志你需要使用&和==:

**

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++技巧。

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

我以前使用过的一个示例应用程序是,假设您将彩色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);

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

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

掩码将前8位变为0,旧的alpha值在这里。alpha值向上移动到它将采用的最终位位置,然后将其"或"运算为屏蔽像素值。最终结果是0x45345678,它被存储到像素中。

当您想在一个数字中对多层信息进行编码时,会使用比特掩码。

因此(假设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

您需要对数字的二进制表示和逻辑运算符有深入的了解,才能理解位字段。