【问题标题】:How to use bitmask?如何使用位掩码?
【发布时间】:2013-09-03 12:04:39
【问题描述】:

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

【问题讨论】:

标签: c++ c++11 bitmask


【解决方案1】:

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

位标志是一种在一个变量中存储多个不互斥的值的方法。你可能以前见过他们。每个标志都是一个位位置,可以设置为开或关。然后你有一堆位掩码#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;



**

警告:请勿使用等式运算符(即位标志 == 位掩码) 用于测试是否设置了标志-该表达式仅在以下情况下为真 该标志已设置,所有其他标志均未设置。测试单个标志 你需要使用 & 和 == :

**

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

【讨论】:

  • 在您关于位标志的示例中,它如何知道哪个位属于哪个变量?它在字节中的位置,或者字节的实际值打开和关闭某些功能?
【解决方案2】:

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

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

【讨论】:

  • 我不明白,你是说 0xF800 基本上是一组从中选择的位(也就是按地址从一组字节中提取这些位)?我认为位掩码基本上是一个与数据大小相同的 int(因此在这种情况下它将是 48 位)并且掩码被应用在顶部,当掩码的值为 1 时,底层位的值会显示出来,当它为零时,它不会,让您忽略关闭位?换班是为了什么?
  • @MarcusJ:请参考下面 goGud 的示例,它提供了有关位掩码的更多详细信息(即stackoverflow.com/questions/18591924/how-to-use-bitmask/…
  • 我是个白痴。我知道位掩码是什么,但我没有意识到 RGB 三元组不是每个 8 位,这引起了我的困惑。感谢您的帮助! :)
  • @MarcusJ:RGB 三元组每个通道可以是 8 位,通常是。但是有一些 RGB 格式的通道可以小于 8 位,例如 5、6、5,因此 RGB 可以适合 16 位。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案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
    

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

    【讨论】:

    • 为什么 6 & 4 是真的呢?这里实际发生了什么数学运算?
    • 二进制数是 0 或 1。4 是 100,6 是 110数字,每个二进制数字。
    • @LaurieSearn 100110 的按位与是 = 100 为什么是 100 TRUE?
    • @A-Sharabiani:取决于评估方式。 000 通常被评估为 FALSE。如果任何0 值切换到1,则它通常评估为 TRUE。
    猜你喜欢
    • 1970-01-01
    • 2022-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多