检查第n位是否设置为字节的函数

liv*_*hak 19 c bit-manipulation

我想要一个简单的C函数,如果一个字节中的第n位被设置为,它将返回true 1.否则它将返回false.

这在执行时间方面是一个关键功能,因此我正在考虑最佳的方法.

pax*_*blo 37

以下功能可以满足您的需求:

int isNthBitSet (unsigned char c, int n) {
    static unsigned char mask[] = {128, 64, 32, 16, 8, 4, 2, 1};
    return ((c & mask[n]) != 0);
}
Run Code Online (Sandbox Code Playgroud)

这假定为8位字节(不是C中给出的),第0位是最高位的.如果这些假设不正确,那么它只是归结为扩展和/或重新排序mask数组.

没有进行错误检查,因为您将速度视为最重要的考虑因素.难道不是一个无效的传球n,那将是不确定的行为.

在疯狂的优化水平-O3,gcc给我们:

isNthBitSet:    pushl   %ebp
                movl    %esp, %ebp
                movl    12(%ebp), %eax
                movzbl  8(%ebp), %edx
                popl    %ebp
                testb   %dl, mask(%eax)
                setne   %al
                movzbl  %al, %eax
                ret
mask:           .byte   -128, 64, 32, 16, 8, 4, 2, 1
Run Code Online (Sandbox Code Playgroud)

这是非常小而有效的.如果你使它静态并建议内联,或强制它内联作为宏定义,你甚至可以绕过函数调用的成本.

只要确保你对你给出的任何解决方案进行基准测试,包括这个(a).优化中的头号口号是"措施,不要猜!"

如果您想知道按位运算符的工作方式,请参见此处.简化的AND-only版本如下.

&仅当两个位在tewo源中设置时,AND操作才会在目标中设置一个位.相关表格是:

AND | 0 1
----+----
 0  | 0 0
 1  | 0 1
Run Code Online (Sandbox Code Playgroud)

对于给定char值,我们使用单比特位掩码来检查是否设置了一个位.假设你有值13,你想看看是否设置了第三个从最低位开始的位.

Decimal  Binary
  13     0000 1101
   4     0000 0100 (the bitmask for the third-from-least bit).
         =========
         0000 0100 (the result of the AND operation).
Run Code Online (Sandbox Code Playgroud)

您可以看到掩码中的所有零位导致等效结果位为零.掩码中的单个位基本上会让值中的等效位流入结果.如果我们检查的位为零,则结果为零;如果为1,则结果为非零.

这就是return声明中表达式的来源.mask查找表中的值都是单位掩码:

Decimal  Binary
  128    1000 0000
   64    0100 0000
   32    0010 0000
   16    0001 0000
    8    0000 1000
    4    0000 0100
    2    0000 0010
    1    0000 0001
Run Code Online (Sandbox Code Playgroud)

(a) 知道有多好,但你没有:-)

  • 查找表,是的!但我希望第0位是字节中最不重要的位,因此会颠倒`mask []`初始化条目的顺序. (3认同)
  • @blueshift,当然这是你的权利.我只是在解释.而你_never_假设某事更快或更慢,你总是检查.如果你这样做,我会更倾向于听你的.在我的机器上对这个函数进行基准测试,优化`-O0`(无)在千分之四秒内完成了一百万次检查,这是每秒二亿五千万次(尽管如此,它是一个庞大的八核开发盒) .如果您需要更好,那么请务必选择更快的解决方案.就个人而言,我怀疑除非在最极端的情况下才有必要. (2认同)

Jon*_*Jon 24

只需检查值(1 << bit) & byte.如果它非零,则设置该位.


Div*_*vya 11

让数字为num.然后:

return ((1 << n) & num);
Run Code Online (Sandbox Code Playgroud)