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

seb*_*ebi 12 c bit-manipulation bitmask

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

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

例如:

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

还有什么是面具?

Jer*_*fin 25

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

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

  • 请记住,去往`1 << w - 1`,其中`w`是数据类型的宽度,设置除了其中一个位之外的所有位,都是UB. (3认同)

Ale*_*nze 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产量2 n.在二进制中,它是10 ... 0和n0.

(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;
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为@UlrichEckhardt 的意思是,如果 msb 定义了包含的最高有效位(这是典型用法),那么您的掩码就太短了 1 位。根据包容性定义,最高有效位 1 应选择位 1 和 0,因此掩码为 0x3,但您的代码生成 0x1。`src = 1LL &lt;&lt; (msb + 1)` 更好。或者 - 将变量名称从“msb”更改为“num_of_bits”,然后你是正确的。 (2认同)