16

有人可以向我解释一下这个功能吗?

最低有效 n 位设置为 1 的掩码。

前任:

n = 6 --> 0x2F, n = 17 --> 0x1FFFF // 我一点也不明白,尤其是 n = 6 --> 0x2F

还有,什么是口罩?

4

6 回答 6

31

通常的方法是取 a 1,并将其向左移动n。这会给你类似的东西:00100000. 然后从中减去一个,这将清除已设置的位,并设置所有次要有效位,因此在这种情况下,我们将得到:00011111

掩码通常用于按位运算,尤其是and. 您将使用上面的掩码自己获取 5 个最低有效位,与可能存在的任何其他内容隔离。这在处理通常具有单个硬件寄存器的硬件时尤其常见,该寄存器包含表示许多完全独立的、不相关的数量和/或标志的位。

于 2012-09-14T00:35:37.307 回答
10

掩码是一个整数值的常用术语,它与另一个整数值按位与、或、异或等。

例如,如果您想提取一个 int 变量的 8 个最低有效数字,您可以使用variable & 0xFF. 0xFF 是一个掩码。

同样,如果您想设置位 0 和 8,您可以这样做variable | 0x101,其中 0x101 是掩码。

或者,如果您想反转相同的位,您可以这样做variable ^ 0x101,其中 0x101 是掩码。

要为您的情况生成一个掩码,您应该利用一个简单的数学事实,即如果您将 1 添加到您的掩码(掩码的所有最低有效位都设置为 1,其余位设置为 0),您将获得一个值为2.

所以,如果你生成最接近的 2 的幂,那么你可以从中减去 1 来得到掩码。

使用 C中的左移<<运算符很容易生成 2 的正幂。

因此,1 << n产生 2 n。在二进制中,它是 10...0 和n0。

(1 << n) - 1将产生一个n最低位设置为 1 的掩码。

现在,您需要注意左移时的溢出。在 C(和 C++)中,您不能合法地将变量左移尽可能多的位位置,因此如果 int 是 32 位,则1<<32结果为undefined behavior. 还应避免有符号整数溢出,因此应使用无符号值,例如1u << 31.

于 2012-09-14T00:45:31.557 回答
9

由于现代 x86 处理器(特别是 BLSMSK)中 BMI 指令的出现,自 2012 年问及这个问题以来,实现这一点的最佳方法已经改变。

这是解决此问题的好方法,同时保持与旧处理器的向后兼容性。

这种方法是正确的,而当前的最佳答案在极端情况下会产生未定义的行为。

当允许使用 BMI 指令进行优化时,Clang 和 GCC 会将 gen_mask() 压缩为两个操作。使用支持硬件,请务必为 BMI 指令添加编译器标志: -mbmi -mbmi2

#include <inttypes.h>
#include <stdio.h>

uint64_t gen_mask(const uint_fast8_t msb) {
  const uint64_t src = (uint64_t)1  << msb;
  return (src - 1) ^ src;
}

int main() {
  uint_fast8_t msb;
  for (msb = 0; msb < 64; ++msb) {
    printf("%016" PRIx64 "\n", gen_mask(msb));
  }
  return 0;
}
于 2015-06-29T19:36:40.953 回答
1

首先,对于那些只想要代码来创建面具的人:

uint64_t bits = 6;
uint64_t mask = ((uint64_t)1 << bits) - 1;
# Results in 0b111111 (or 0x03F)

对于那些想知道面具是什么的人:

掩码通常是值的名称,我们使用它来使用按位运算(如 AND、OR、XOR 等)来操作其他值。

短掩码通常以二进制表示,我们可以明确地看到所有设置为 1 的位。

较长的掩码通常以十六进制表示,一旦掌握它就很容易阅读。

您可以在此处阅读有关 C 中的按位运算的更多信息,以便更好地掌握材料。

于 2019-04-29T10:52:17.130 回答
0

我相信你的第一个例子应该是0x3f.

0x3f63是二进制数字的十六进制表示法111111,因此最后 6 位(最低有效 6 位)设置为1.

下面的小 C 程序将计算正确的掩码:

#include <stdarg.h>
#include <stdio.h>

int mask_for_n_bits(int n)
{
    int mask = 0;

    for (int i = 0; i < n; ++i)
        mask |= 1 << i;

    return mask;
}

int main (int argc, char const *argv[])
{
    printf("6: 0x%x\n17: 0x%x\n", mask_for_n_bits(6), mask_for_n_bits(17));
    return 0;
}
于 2012-09-14T00:38:00.763 回答
0

0x2F0010 1111二进制的 - 这应该是0x3f,它是0011 1111二进制的并且设置了 6 个最低有效位。

同样,0x1FFFF0001 1111 1111 1111 1111二进制的,它设置了 17 个最低有效位。

“掩码”是一个值,它旨在使用按位运算符(如 )与另一个值组合&|或者^单独设置、取消设置、翻转或保持其他值中的位不变。

例如,如果您使用运算符将​​掩码0x2F与某个值组合,则结果将在除 6 个最低有效位之外的所有位中都为零,并且这 6 个位将从 value 中原样复制。n&n

在掩码的情况下,&掩码中的二进制0表示“无条件地将结果位设置为 0”,a1表示“将结果位设置为输入值位”。对于|掩码,掩码中的 an0将结果位设置为输入位,a1无条件地将结果位设置为1,对于^掩码,0将结果位设置为输入位,a1将结果位设置为输入位。

于 2012-09-14T00:38:35.050 回答