你如何设置,清除和切换一个位?

c++ c bit-manipulation bitwise-operators

1062893 观看

27回复

20744 作者的声誉

如何在C / C ++中设置,清除和切换?

作者: JeffV 的来源 发布者: 2008 年 9 月 7 日

回应 27


35

9268 作者的声誉

使用按位运算符: & |

要设置最后一位000b

foo = foo | 001b

检查最后一位foo

if ( foo & 001b ) ....

清除最后一点foo

foo = foo & 110b

我用来XXXb表示清晰。您可能正在使用HEX表示,具体取决于您打包位的数据结构。

作者: nsanders 发布者: 2008 年 9 月 7 日

3352

130118 作者的声誉

决定

设置一下

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

number |= 1UL << n;

这将n是最重要的numbern应该为零,如果要设置1st位,依此类推n-1,如果要设置该n位。

使用1ULLif number比宽unsigned long; 1UL << n直到评估1UL << n了未定义的行为偏移超过a的宽度之后才会发生促销long。这同样适用于所有其他示例。

清理一下

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

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

这将清除一n点点number。必须使用按位NOT运算符(~)反转位串,然后运行AND。

切换了一下

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

number ^= 1UL << n;

这将切换到n第二位number

检查一下

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

要检查一下,将数字n向右移动,然后按位向右移动:

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

这将把n第四位的值number放入变量中bit

将第n位更改为x

将该n位设置为1或者0可以通过以下2的补码C ++实现来实现:

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

n,如果将被设置x1,如果清除x0。如果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);

使用无符号类型进行便携式位操作通常是个好主意。

要么

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

(number & ~(1UL << n))将清除该n位并将(x << n)n位置位x

一般来说,通常不要复制/粘贴代码也是一个好主意,因此许多人使用预处理器宏(如社区维基回答更进一步)或某种封装。

作者: Jeremy Ruten 发布者: 2008 年 9 月 7 日

111

81066 作者的声誉

它有时是值得使用enum命名的位:

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

然后使用名称。即写

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

设置,清除和测试。这样您就可以隐藏其余代码中的幻数。

除此之外,我赞同杰里米的解决方案。

作者: dmckee 发布者: 2008 年 9 月 8 日

229

82206 作者的声誉

另一种选择是使用位字段:

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

这仅适用于固定大小的位字段。否则你必须采用之前帖子中描述的比特技巧。

作者: Ferruccio 发布者: 2008 年 9 月 11 日

42

1011 作者的声誉

snip-c.zip的bitops.h:

/*
**  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或long上也能正常工作。

最重要的是,这是一整类问题的一般解决方案。当然,每次需要时,使用显式掩码值重写这些宏的等价物是可能的,甚至是恰当的,但为什么呢?请记住,宏替换发生在预处理器中,因此生成的代码将反映编译器认为值是常量的事实 - 即每次需要时使用通用宏来“重新发明轮子”同样有效做点操作。

不服气?这里有一些测试代码 - 我使用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] ------------------------------------------- ----------------------

作者: yogeesh 发布者: 2008 年 9 月 17 日

13

1363 作者的声誉

如果你做了很多事情,你可能想要使用面具,这将使整个事情变得更快。以下函数非常快并且仍然灵活(它们允许在任何大小的位图中进行位错)。

const unsigned char TQuickByteMask[8] =
{
   0x01, 0x02, 0x04, 0x08,
   0x10, 0x20, 0x40, 0x80,
};


/** Set bit in any sized bit mask.
 *
 * @return    none
 *
 * @param     bit    - Bit number.
 * @param     bitmap - Pointer to bitmap.
 */
void TSetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] |= TQuickByteMask[n];        // Set bit.
}


/** Reset bit in any sized mask.
 *
 * @return  None
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TResetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] &= (~TQuickByteMask[n]);    // Reset bit.
}


/** Toggle bit in any sized bit mask.
 *
 * @return   none
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TToggleBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] ^= TQuickByteMask[n];        // Toggle bit.
}


/** Checks specified bit.
 *
 * @return  1 if bit set else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitSet( short bit, const unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;    // Index to byte.
    n = bit % 8;    // Specific bit in byte.

    // Test bit (logigal AND).
    if (bitmap[x] & TQuickByteMask[n])
        return 1;

    return 0;
}


/** Checks specified bit.
 *
 * @return  1 if bit reset else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitReset( short bit, const unsigned char *bitmap)
{
    return TIsBitSet(bit, bitmap) ^ 1;
}


/** Count number of bits set in a bitmap.
 *
 * @return   Number of bits set.
 *
 * @param    bitmap - Pointer to bitmap.
 * @param    size   - Bitmap size (in bits).
 *
 * @note    Not very efficient in terms of execution speed. If you are doing
 *        some computationally intense stuff you may need a more complex
 *        implementation which would be faster (especially for big bitmaps).
 *        See (http://graphics.stanford.edu/~seander/bithacks.html).
 */
int TCountBits( const unsigned char *bitmap, int size)
{
    int i, count = 0;

    for (i=0; i<size; i++)
        if (TIsBitSet(i, bitmap))
            count++;

    return count;
}

注意,要在16位整数中设置位'n',请执行以下操作:

TSetBit( n, &my_int);

It's up to you to ensure that the bit number is within the range of the bit map that you pass. Note that for little endian processors that bytes, words, dwords, qwords, etc., map correctly to each other in memory (main reason that little endian processors are 'better' than big-endian processors, ah, I feel a flame war coming on...).

作者: Tim Ring 发布者: 2008 年 9 月 17 日

434

204756 作者的声誉

使用标准C ++库:std::bitset<N>

Boost版本: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

标准库编译时大小的bitset相比,Boost版本允许运行时大小的bitset。

作者: Martin York 发布者: 2008 年 9 月 18 日

157

11 作者的声誉

我使用头文件中定义的宏来处理位集和清除:

/* 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))))        // '!!' to make sure this returns 0 or 1

/* 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))
作者: Steve Karg 发布者: 2008 年 11 月 4 日

23

46654 作者的声誉

位域方法在嵌入式领域具有其他优势。您可以定义一个直接映射到特定硬件寄存器中的位的结构。

struct HwRegister {
    unsigned int errorFlag:1;  // one-bit flag field
    unsigned int Mode:3;       // three-bit mode field
    unsigned int StatusCode:4;  // four-bit status code
};

struct HwRegister CR3342_AReg;

您需要了解位打包顺序 - 我认为它首先是MSB,但这可能与实现有关。此外,验证编译器处理程序字段如何跨越字节边界。

然后,您可以像以前一样读取,写入,测试各个值。

作者: Roddy 发布者: 2008 年 11 月 6 日

19

161511 作者的声誉

检查任意类型变量中任意位置的位:

#define bit_test(x, y)  ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

样品用法:

int main(void)
{
    unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };

    for (int ix = 0; ix < 64; ++ix)
        printf("bit %d is %d\n", ix, bit_test(arr, ix));

    return 0;
}

注意: 这是为了快速(具有灵活性)和非分支。在编译Sun Studio 8时,它可以生成高效的SPARC机器代码; 我还在amd64上使用MSVC ++ 2008测试了它。可以制作类似的宏来设置和清除位。与其他许多解决方案相比,此解决方案的主要区别在于它适用于几乎任何类型的变量中的任何位置。

作者: John Zwinck 发布者: 2009 年 1 月 3 日

11

0 作者的声誉

Use this:

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

    return num;
}
作者: thangavel 发布者: 2009 年 4 月 11 日

19

1167 作者的声誉

更一般地说,对于任意大小的位图:

#define BITS 8
#define BIT_SET(  p, n) (p[(n)/BITS] |=  (0x80>>((n)%BITS)))
#define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS)))
#define BIT_ISSET(p, n) (p[(n)/BITS] &   (0x80>>((n)%BITS)))
作者: bill 发布者: 2009 年 6 月 13 日

25

161611 作者的声誉

这里是我最喜欢的位算术宏,这对于任何类型的无符号整数数组的作品从unsigned charsize_t(这是应该是有效的一起工作最大的类型):

#define BITOP(a,b,op) \
 ((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))

设置一下:

BITOP(array, bit, |=);

要清楚一点:

BITOP(array, bit, &=~);

要切换一下:

BITOP(array, bit, ^=);

测试一下:

if (BITOP(array, bit, &)) ...

等等

作者: R.. 发布者: 2010 年 7 月 13 日

13

131 作者的声誉

该程序将任何数据位从0更改为1或1更改为0:

{
    unsigned int data = 0x000000F0;
    int bitpos = 4;
    int bitvalue = 1;
    unsigned int bit = data;
    bit = (bit>>bitpos)&0x00000001;
    int invbitvalue = 0x00000001&(~bitvalue);
    printf("%x\n",bit);

    if (bitvalue == 0)
    {
        if (bit == 0)
            printf("%x\n", data);
        else
        {
             data = (data^(invbitvalue<<bitpos));
             printf("%x\n", data);
        }
    }
    else
    {
        if (bit == 1)
            printf("elseif %x\n", data);
        else
        {
            data = (data|(bitvalue<<bitpos));
            printf("else %x\n", data);
        }
    }
}
作者: Gokul Naathan 发布者: 2012 年 2 月 28 日

6

201 作者的声誉

使用此处定义的运算符之一。

要设置一个位,用来int x = x | 0x?;在那里?是二进制形式的比特位置。

作者: Jason 发布者: 2012 年 4 月 30 日

31

892 作者的声誉

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

例:

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)
作者: kapilddit 发布者: 2012 年 6 月 5 日

23

1671 作者的声誉

由于这被标记为“嵌入式”,我假设您正在使用微控制器。所有上述建议都是有效的和工作(读 - 修改 - 写,工会,结构等)。

但是,在基于示波器的调试过程中,我惊讶地发现,与直接将值写入微型PORTnSET / PORTnCLEAR寄存器相比,这些方法在CPU周期中具有相当大的开销,这使得存在紧密环路/高电平时会产生真正的差异-frequency ISR的切换引脚。

对于那些不熟悉的人:在我的例子中,micro有一个通用的引脚状态寄存器PORTn,它反映了输出引脚,所以做PORTn | = BIT_TO_SET会导致对该寄存器的读 - 修改 - 写。但是,PORTnSET / PORTnCLEAR寄存器取“1”表示“请将此位1”(SET)或“请将此位置零”(CLEAR),将“0”表示“保持引脚单独”。所以,你最终有两个端口地址取决于不管你是设置或清除位(并不总是很方便),但很多更快的反应和更小的汇编代码。

作者: John U 发布者: 2012 年 6 月 14 日

9

0 作者的声誉

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设置和清除bool很容易。

要找到不可打印的字符:

//  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个月后,证明我们从中获取数据的主机系统实际上是故障。比特阵列的简单性使得它们的正确性非常高 - 例如,与搜索方法相比。

作者: user1899861 发布者: 2012 年 12 月 30 日

10

881 作者的声誉

Expanding on the bitset answer:

#include <iostream>
#include <bitset>
#include <string>

using namespace std;
int main() {
  bitset<8> byte(std::string("10010011");

  // Set Bit
  byte.set(3); // 10010111

  // Clear Bit
  byte.reset(2); // 10010101

  // Toggle Bit
  byte.flip(7); // 00010101

  cout << byte << endl;

  return 0;
}
作者: kendotwill 发布者: 2014 年 5 月 8 日

-2

39 作者的声誉

在C语言中尝试使用其中一个函数来改变n位:

char bitfield;

// Start at 0th position

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}

要么

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}

要么

void chang_n_bit(int n, int value)
{
    if(value)
        bitfield |= 1 << n;
    else
        bitfield &= ~0 ^ (1 << n);
}

char get_n_bit(int n)
{
    return (bitfield & (1 << n)) ? 1 : 0;
}
作者: Vincet 发布者: 2014 年 5 月 27 日

5

310 作者的声誉

这是我使用的一些宏:

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)
作者: sam msft 发布者: 2015 年 2 月 6 日

10

14347 作者的声誉

If you want to perform this all operation with C programming in the Linux kernel then I suggest to use standard APIs of the Linux kernel.

See 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计算机上都是原子的,并且有助于保持处理器之间的一致性。

作者: Jeegar Patel 发布者: 2016 年 5 月 27 日

4

87373 作者的声誉

你如何设置,清除和切换一个位?

To address a common coding pitfall when attempting to form the mask:
1 is not always wide enough

What problems happen when number is a wider type than 1?
x may be too great for the shift 1 << x leading to undefined behavior (UB). Even if x is not too great, ~ may not flip enough most-significant-bits.

// assume 32 bit int/unsigned
unsigned long long number = foo();

unsigned x = 40; 
number |= (1 << x);  // UB
number ^= (1 << x);  // UB
number &= ~(1 << x); // UB

x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough

To insure 1 is wide enough:

Code could use 1ull or pedantically (uintmax_t)1 and let the compiler optimize.

number |= (1ull << x);
number |= ((uintmax_t)1 << x);

Or cast - which makes for coding/review/maintenance issues keeping the cast correct and up-to-date.

number |= (type_of_number)1 << x;

Or gently promote the 1 by forcing a math operation that is as least as wide as the type of number.

number |= (number*0 + 1) << x;

As with most bit manipulations, best to work with unsigned types rather than signed ones

作者: chux 发布者: 2017 年 9 月 27 日

3

320 作者的声誉

A C++11 templated version (put in a header):

namespace bit {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bit) {variable |=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bit) {variable ^=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);}
}

namespace bitmask {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bits) {variable |= bits;}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bits) {variable &= ~bits;}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bits) {variable ^= bits;}
    template <typename T1, typename T2> inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);}
    template <typename T1, typename T2> inline bool test_any(T1 &variable, T2 bits) {return variable & bits;}
}
作者: Joakim L. Christiansen 发布者: 2018 年 2 月 10 日

4

17135 作者的声誉

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);
}
作者: Sazzad Hissain Khan 发布者: 2018 年 2 月 21 日

5

122 作者的声誉

使用变量

int value, pos;

value - 数据
位置 - 我们有兴趣设置,清除或切换的位的位置。

设置一下:

value = value | 1 << pos;

清楚一点:

value = value & ~(1 << pos); 

切换一下:

value = value ^ 1 << pos;
作者: Jeet Parikh 发布者: 2018 年 7 月 11 日

1

1252 作者的声誉

Let suppose few things first
num = 55 Integer to perform bitwise operations (set, get, clear, toggle).
n = 4 0 based bit position to perform bitwise operations.

How to get a bit?

  1. To get the nth bit of num right shift num, n times. Then perform bitwise AND & with 1.
bit = (num >> n) & 1;

How it works?

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

How to set a bit?

  1. To set a particular bit of number. Left shift 1 n times. Then perform bitwise OR | operation with num.
num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

How it works?

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

How to clear a bit?

  1. Left shift 1, n times i.e. 1 << n.
  2. 用上述结果执行按位补码。因此第n位变为未设置,其余位变为设置即~ (1 << n)
  3. 最后,&使用上述结果执行按位AND 运算num。以上三个步骤可以写成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)

推荐阅读 - 按位运算符练习

作者: Pankaj Prakash 发布者: 2019 年 6 月 10 日
32x32