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


当前回答

该程序基于@Jeremy的上述解决方案。如果有人想快速玩耍。

public class BitwiseOperations {

    public static void main(String args[]) {

        setABit(0, 4); // set the 4th bit, 0000 -> 1000 [8]
        clearABit(16, 5); // clear the 5th bit, 10000 -> 00000 [0]
        toggleABit(8, 4); // toggle the 4th bit, 1000 -> 0000 [0]
        checkABit(8,4); // check the 4th bit 1000 -> true 
    }

    public static void setABit(int input, int n) {
        input = input | ( 1 << n-1);
        System.out.println(input);
    }


    public static void clearABit(int input, int n) {
        input = input & ~(1 << n-1);
        System.out.println(input);
    }

    public static void toggleABit(int input, int n) {
        input = input ^ (1 << n-1);
        System.out.println(input);
    }

    public static void checkABit(int input, int n) {
        boolean isSet = ((input >> n-1) & 1) == 1; 
        System.out.println(isSet);
    }
}


Output :
8
0
0
true

其他回答

对于初学者,我想用一个例子解释一下:

例子:

value is 0x55;
bitnum : 3rd.

使用&运算符检查位:

0101 0101
&
0000 1000
___________
0000 0000 (mean 0: False). It will work fine if the third bit is 1 (then the answer will be True)

切换或翻转:

0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)

|运算符:设置位

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)

设置一位

使用按位OR运算符(|)设置位。

number |= 1UL << n;

这将设置数字的第n位。如果要将第1位设置为n-1,那么n应该为零,如果要设置第n位。

如果数字大于无符号长,则使用1ULL;1UL<<n的提升直到评估1UL<<n之后才发生,其中移动超过长的宽度是未定义的行为。这同样适用于所有其他示例。

清除一点

使用位AND运算符(&)清除位。

number &= ~(1UL << n);

这将清除数字的第n位。必须使用按位NOT运算符(~)反转位字符串,然后对其进行AND运算。

稍微扭动一下

XOR运算符(^)可用于切换位。

number ^= 1UL << n;

这将切换数字的第n位。

检查一点

你没有要求这样做,但我不妨补充一下。

要检查一位,请向右移动数字n,然后按位“与”:

bit = (number >> n) & 1U;

这将把数字第n位的值放入变量位。

将第n位更改为x

在2的补码C++实现中,可以通过以下方式将第n位设置为1或0:

number ^= (-x ^ number) & (1UL << n);

如果x为1,则设置位n,如果x为0,则清除位n。如果x有其他值,则会得到垃圾。x=!!x将其布尔化为0或1。

要使其独立于2的补码否定行为(其中-1设置了所有位,与1的补码或符号/大小C++实现不同),请使用无符号否定。

number ^= (-(unsigned long)x ^ number) & (1UL << n);

or

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

使用无符号类型进行可移植位操作通常是一个好主意。

or

number = (number & ~(1UL << n)) | (x << n);

(number&~(1UL<<n))将清除第n位,(x<<n)将第n位设置为x。

一般来说,不复制/粘贴代码也是一个好主意,因为很多人使用预处理器宏(如社区wiki答案)或某种封装。

将第n位设置为x(位值),不使用-1

有时,当您不确定-1或类似的结果时,您可能希望在不使用-1的情况下设置第n位:

number = (((number | (1 << n)) ^ (1 << n))) | (x << n);

解释:((number |(1<<n)将第n位设置为1(其中|表示逐位OR),然后使用(…)^(1<<n)将将第n个位设置为0,最后通过(…)|x<<n,将第n比特设置为0(位值)x。

这也适用于戈朗。

有时值得使用枚举来命名位:

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

然后稍后使用这些名称,即写

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

设置、清除和测试。通过这种方式,您可以对代码的其余部分隐藏神奇的数字。

除此之外,我支持佩奇·鲁滕的解决方案。

如果您想在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计算机上,这些都保证是原子的,并且是有用的以保持处理器之间的一致性。