如何设置、清除和切换一点?


当前回答

下面是我使用的一些宏:

SET_FLAG(Status, Flag)            ((Status) |= (Flag))
CLEAR_FLAG(Status, Flag)          ((Status) &= ~(Flag))
INVALID_FLAGS(ulFlags, ulAllowed) ((ulFlags) & ~(ulAllowed))
TEST_FLAGS(t,ulMask, ulBit)       (((t)&(ulMask)) == (ulBit))
IS_FLAG_SET(t,ulMask)             TEST_FLAGS(t,ulMask,ulMask)
IS_FLAG_CLEAR(t,ulMask)           TEST_FLAGS(t,ulMask,0)

其他回答

int set_nth_bit(int num, int n){    
    return (num | 1 << n);
}

int clear_nth_bit(int num, int n){    
    return (num & ~( 1 << n));
}

int toggle_nth_bit(int num, int n){    
    return num ^ (1 << n);
}

int check_nth_bit(int num, int n){    
    return num & (1 << n);
}

如果您想在Linux内核中使用C编程执行所有操作,那么我建议使用Linux内核的标准API。

看见https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html

set_bit  Atomically set a bit in memory
clear_bit  Clears a bit in memory
change_bit  Toggle a bit in memory
test_and_set_bit  Set a bit and return its old value
test_and_clear_bit  Clear a bit and return its old value
test_and_change_bit  Change a bit and return its old value
test_bit  Determine whether a bit is set

注意:这里整个操作在一个步骤中完成。因此,即使在SMP计算机上,这些都保证是原子的,并且是有用的以保持处理器之间的一致性。

使用此项:

int ToggleNthBit ( unsigned char n, int num )
{
    if(num & (1 << n))
        num &= ~(1 << n);
    else
        num |= (1 << n);

    return num;
}

Visual C 2010,也许还有许多其他编译器,都直接支持内置的布尔运算。一个位有两个可能的值,就像一个布尔值一样,所以我们可以使用布尔值,即使在这种表示中,布尔值占用的内存空间比一个位多。这是有效的,即使sizeof()运算符也能正常工作。

bool    IsGph[256], IsNotGph[256];

//  Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++)  {
    IsGph[i] = isgraph((unsigned char)i);
}

因此,对于您的问题,IsGph[i]=1或IsGph[i]=0使得设置和清除布尔值变得容易。

要查找不可打印的字符:

//  Initialize boolean array to detect UN-printable characters, 
//  then call function to toggle required bits true, while initializing a 2nd
//  boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++)  {
    if(IsGph[i])    {
         IsNotGph[i] = 0;
    }   else   {
         IsNotGph[i] = 1;
    }
}

注意,这段代码没有什么“特殊”之处。它有点像一个整数-从技术上讲,它是一个1位整数,可以容纳2个值,并且只能容纳2个。

我曾经使用这种方法查找重复的贷款记录,其中loan_number是ISAM密钥,使用6位贷款编号作为位数组的索引。8个月后,我们以惊人的速度证明了我们从中获取数据的主机系统实际上发生了故障。比特阵列的简单性使人们对其正确性的信心非常高——例如,与搜索方法相比。

先假设几件事num=55整数以执行逐位操作(set、get、clear、toggle)。n=4 0位位置,以执行逐位操作。

如何获得一点?

要获得num的第n位,请右移num,n次。然后用1执行逐位AND&。

bit = (num >> n) & 1;

它是如何工作的?

       0011 0111 (55 in decimal)
    >>         4 (right shift 4 times)
-----------------
       0000 0011
     & 0000 0001 (1 in decimal)
-----------------
    => 0000 0001 (final result)

如何设置一点?

设置数字的特定位。左移1 n次。然后用num。

num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

它是如何工作的?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     | 0011 0111 (55 in decimal)
-----------------
    => 0001 0000 (final result)

如何清除一点?

左移1,n次,即1<<n。对上述结果执行按位补码。因此,第n位变为未置位,其余位变为置位,即~(1<<n)。最后,对上述结果和num执行逐位AND&运算。上述三个步骤一起可以写成num&(~(1<<n));

num &= (~(1 << n));    // Equivalent to; num = num & (~(1 << n));

它是如何工作的?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
     ~ 0001 0000
-----------------
       1110 1111
     & 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

如何切换一点?

要切换位,我们使用逐位XOR^运算符。如果两个操作数的对应位不同,则逐位XOR运算符的计算结果为1,否则计算结果为0。

这意味着要切换一个位,我们需要对要切换的位和1执行XOR运算。

num ^= (1 << n);    // Equivalent to; num = num ^ (1 << n);

它是如何工作的?

如果要切换的位为0,则0 ^1=>1。如果要切换的位为1,则1^1=>0。

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     ^ 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

推荐阅读-按位操作员练习