如何在C / C ++中设置,清除和切换?
如何在C / C ++中设置,清除和切换?
使用按位OR运算符(|
)设置一下。
number |= 1UL << n;
这将设置 n
一点点 number
。
使用 1ULL
如果 number
比...宽 unsigned long
;促进 1UL << n
直到评估后才会发生 1UL << n
它的未定义行为偏移超过a的宽度 long
。这同样适用于所有其他示例。
使用按位AND运算符(&
)清楚一点。
number &= ~(1UL << n);
这将清除 n
一点点 number
。必须使用按位NOT运算符反转位串(~
),然后和它。
XOR运算符(^
)可以用来切换一下。
number ^= 1UL << n;
这将切换 n
一点点 number
。
你没有要求这个,但我不妨补充一下。
要检查一下,将数字n向右移动,然后按位移动它:
bit = (number >> n) & 1U;
这将是值得的 n
一点点 number
进入变量 bit
。
设置 n
两点都有 1
要么 0
可以通过以下2的补码C ++实现来实现:
number ^= (-x ^ number) & (1UL << n);
位 n
将被设置如果 x
是 1
,如果 x
是 0
。如果 x
还有其他价值,你得到垃圾。 x = !!x
将它布尔化为0或1。
使其独立于2的补充否定行为(其中 -1
设置所有位,与1的补码或符号/幅度C ++实现不同),使用无符号否定。
number ^= (-(unsigned long)x ^ number) & (1UL << n);
要么
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
使用无符号类型进行便携式位操作通常是个好主意。
一般来说,通常不要复制/粘贴代码也是一个好主意,所以很多人都使用预处理器宏(比如 社区维基进一步回答)或某种封装。
使用标准C ++库: std::bitset<N>
。
或者 促进 版: boost::dynamic_bitset
。
没有必要自己动手:
#include <bitset>
#include <iostream>
int main()
{
std::bitset<5> x;
x[1] = 1;
x[2] = 0;
// Note x[0-4] valid
std::cout << x << std::endl;
}
[Alpha:] > ./a.out
00010
与a相比,Boost版本允许运行时大小的bitset 标准库 编译时大小的bitset。
另一种选择是使用位字段:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
定义一个3位字段(实际上,它是三个1位字符)。位操作现在变得有点(哈哈)更简单:
设置或清除一下:
mybits.b = 1;
mybits.c = 0;
要切换一下:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
检查一下:
if (mybits.c) //if mybits.c is non zero the next line below will execute
这仅适用于固定大小的位字段。否则你必须采用之前帖子中描述的比特技巧。
我使用头文件中定义的宏来处理位集和清除:
/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) ((a) & (1ULL<<(b)))
/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (((x) & (y)) == (y)) // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))
有时值得使用 enum
至 名称 比特:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
然后使用 名 稍后的。即写
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
设置,清除和测试。这样,您可以隐藏其余代码中的幻数。
除此之外,我赞同杰里米的解决方案。
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/
typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;
#define BOOL(x) (!(!(x)))
#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))
好的,让我们分析一下......
你似乎在所有这些中遇到问题的常见表达是“(1L <<(posn))”。所有这一切都是创建一个单一位的掩码 哪个适用于任何整数类型。 “posn”参数指定了 你想要的位置。如果posn == 0,那么这个表达式将会 评估为:
0000 0000 0000 0000 0000 0000 0000 0001 binary.
如果posn == 8,它将评估为
0000 0000 0000 0000 0000 0001 0000 0000 binary.
换句话说,它只是创建一个0的字段,在指定的位置为1 位置。唯一棘手的部分是我们需要设置的BitClr()宏 1的字段中的单个0位。这是通过使用1来完成的 由波浪号(〜)运算符表示的相同表达式的补码。
一旦创建了蒙版,它就像你建议的那样应用于参数, 通过使用按位和(&),或(|)和xor(^)运算符。自面具 类型为long,宏也可以在char,short,int上工作, 或者长的。
最重要的是,这是整个类的一般解决方案 问题。当然,重写它是可能的,甚至是恰当的 每当您使用显式掩码值时,相当于任何这些宏 需要一个,但为什么呢?请记住,宏替换发生在 预处理器等生成的代码将反映出值的事实 编译器认为它是恒定的 - 即使用它同样有效 每次你需要做的“重新发明轮子”的通用宏 位操纵。
不服气?这是一些测试代码 - 我使用Watcom C进行全面优化 并且不使用_cdecl,因此产生的反汇编将像干净一样 可能:
---- [TEST.C] ----------------------------------------- -----------------------
#define BOOL(x) (!(!(x)))
#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))
int bitmanip(int word)
{
word = BitSet(word, 2);
word = BitSet(word, 7);
word = BitClr(word, 3);
word = BitFlp(word, 9);
return word;
}
---- [TEST.OUT(disassembled)] -------------------------------------- ---------
Module: C:\BINK\tst.c
Group: 'DGROUP' CONST,CONST2,_DATA,_BSS
Segment: _TEXT BYTE 00000008 bytes
0000 0c 84 bitmanip_ or al,84H ; set bits 2 and 7
0002 80 f4 02 xor ah,02H ; flip bit 9 of EAX (bit 1 of AH)
0005 24 f7 and al,0f7H
0007 c3 ret
No disassembly errors
---- [finis] ------------------------------------------- ----------------------
对于初学者,我想用一个例子来解释一下:
例:
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)
|
operator:设置位
0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
使用按位运算符: &
|
设置最后一位 000b
:
foo = foo | 001b
检查最后一位 foo
:
if ( foo & 001b ) ....
要清除最后一位 foo
:
foo = foo & 110b
我用了 XXXb
为清楚起见。您可能正在使用HEX表示,具体取决于您打包位的数据结构。