如何在C中创建最低有效位设置为1的掩码

问题描述 投票:12回答:6

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

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

例如:

n = 6 - > 0x2F,n = 17 - > 0x1FFFF //我根本得不到这些,尤其是n = 6 - > 0x2F

还有什么是面具?

c bit-manipulation bitmask
6个回答
24
投票

通常的方法是采取1,并将其左移n位。这会给你一些像:00100000。然后从中减去一个,这将清除设置的位,并设置所有不太重要的位,所以在这种情况下我们得到:00011111

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


8
投票

掩码是整数值的常用术语,该整数值与另一个整数值进行逐位AND运算,OR运算,XOR运算等。

例如,如果要提取int变量的8个最低有效数字,则执行variable & 0xFF。 0xFF是一个掩码。

同样,如果要设置位0和8,则执行variable | 0x101,其中0x101是掩码。

或者,如果要反转相同的位,则执行variable ^ 0x101,其中0x101是掩码。

要为你的情况生成一个掩码,你应该利用一个简单的数学事实:如果你在掩码中添加1(掩码的所有最低有效位设置为1,其余的为0),你得到的值就是2。

因此,如果您生成最接近2的幂,则可以从中减去1以获得掩码。

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

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

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

现在,您需要注意左移的溢出。在C(和C ++中),你不能合法地将变量左移由变量所具有的位数,因此如果整数是32位,则1<<32会导致undefined behavior。还应避免使用有符号整数溢出,因此应使用无符号值,例如: 1u << 31


8
投票

对于正确性和性能,实现这一目标的最佳方法已经改变,因为在2012年由于现代x86处理器(特别是BLSMSK)中BMI指令的出现而回答了这个问题。

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

此方法是正确的,而当前的顶部答案在边缘情况下产生未定义的行为。

当允许使用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;
}

0
投票

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

0x3f是数字63的十六进制表示法,111111是二进制的1,因此最后6位(最低有效6位)设置为#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; }

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

0x2F

0
投票

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

类似地,0001 1111 1111 1111 1111是二进制的&,它具有17个最低有效位。

“掩码”是一个值,旨在使用像|^0x2F这样的按位运算符与另一个值组合,以单独设置,取消设置,翻转或保持其他值中的位不变。

例如,如果使用n运算符将掩码&与某个值n组合,则结果将在除6个最低有效位之外的所有位中具有零,并且这些6位将从值&未更改地复制。

0掩码的情况下,掩码中的二进制1意味着“无条件地将结果位设置为0”,而|意味着“将结果位设置为输入值位”。对于0掩码,掩码中的1将结果位设置为输入位,1无条件地将结果位设置为^,对于0掩码,1将结果位设置为输入位,uint64_t bits = 6; uint64_t mask = ((uint64_t)1 << bits) - 1; # Results in 0b111111 (or 0x03F) 设置结果位到输入位的补码。


0
投票

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

here

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

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

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

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

您可以在C qazxswpoi中阅读有关按位操作的更多信息,以便更好地掌握材料。

© www.soinside.com 2019 - 2024. All rights reserved.