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


当前回答

使用此项:

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

    return num;
}

其他回答

设置一位

使用按位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。

这也适用于戈朗。

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

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,但这可能取决于实现。此外,验证编译器处理程序字段如何跨越字节边界。

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

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);
}

先假设几件事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)

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