你如何设置、清除和切换一个位?
使用比特OR操作符(|
)来设置一个比特。
number |= 1UL << n;
这将设置number'的第
n位。如果你想设置第
1位,
n应该是0,以此类推,如果你想设置第
n位,
n-1`。
如果 "number "比 "unsigned long "宽,请使用 "1ULL";"1UL <<n "的推广直到评估 "1UL <<n "之后才会发生,在那里,移位超过 "long "的宽度是未定义的行为。 这也适用于所有其他的例子。
使用位与运算符(&
)来清除一个位。
number &= ~(1UL << n);
这将清除number'的第
n位。你必须用比特非运算符(
~`)反转比特字符串,然后再与之相加。
XOR运算符(^
)可以用来切换一个位。
number ^= 1UL << n;
这将切换number'的第
n`位。
你没有要求这个,但我不妨加上。
要检查一个比特,将数字n向右移动,然后将其进行比特化。
bit = (number >> n) & 1U;
这将把number
的第n
位的值放入变量bit
。
将第n
位设置为1
或0
可以在2's complement C++实现上通过以下方式实现。
number ^= (-x ^ number) & (1UL << n);
如果x
为1
,第n
位将被设置,如果x
为0
,则被清除。 如果x
有其他值,你会得到垃圾。 x = !x
将布尔化它为0或1。
为了使其独立于2's补数的否定行为(其中-1
有所有位的设置,与1's补数或符号/大小的C++实现不同),使用无符号否定。
number ^= (-(unsigned long)x ^ number) & (1UL << n);
或
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
一般来说,使用无符号类型来进行可移植位操作是个好主意。
或
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
将清除第n
位,(x << n)
将设置第n
位为x
。
一般来说,不要复制/粘贴代码也是一个好主意,因此许多人使用预处理器宏(如[社区维基答案](https://stackoverflow.com/a/263738/52074))或某种封装。
有时值得使用一个 "enum "来命名位。
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
然后再使用这些名称。例如,写
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
来设置、清除和测试。这样,你就把这些神奇的数字从你的其他代码中隐藏起来。
除此以外,我赞成Jeremy的解决方案。