目录

一、什么是位操作

二、位操作有哪些

三、组合位操作


一、什么是位操作

位操作是指直接对二进制数的位进行操作的一类运算。在计算机中,数据以二进制形式存储和表示,在某些情况下需要对二进制数的位进行特定操作,这就用到了位操作。

位操作通常用于优化代码、实现位级别的标志操作、提取和设置二进制数中的特定位等场景。但需要注意,位操作对于代码的可读性和可维护性可能有一定的影响,应谨慎使用,并确保操作的正确性和逻辑清晰性。

二、位操作有哪些

假设有两个无符号字符变量 ab,它们的二进制表示分别为:

a = 0b10100110b = 0b11001100

常见的位操作包括:

1、按位与(&):将两个数的每一位进行与运算,只有当两个位都为1时,结果才为1,否则为0。

a & b = 0b10000100

此操作将 ab 的每一位进行与运算,只有当两个位都为 1 时,结果位才为 1,否则为 0。

2、按位或(|):将两个数的每一位进行或运算,只有当两个位都为0时,结果才为0,否则为1。

a | b = 0b11101110

此操作将 ab 的每一位进行或运算,只有当两个位都为 0 时,结果位才为 0,否则为 1。

3、按位异或(^):将两个数的每一位进行异或运算,当两个位相同(都为0或都为1)时,结果为0,否则为1。

a ^ b = 0b01101010

此操作将 ab 的每一位进行异或运算,当两个位相同(都为 0 或都为 1)时,结果为 0,否则为 1。

4、按位取反(~):对一个数的每一位进行取反操作,将0变为1,将1变为0。

~a = 0b01011001

此操作对变量 a 的每一位进行取反操作,将 0 变为 1,将 1 变为 0。

5、左移(<<):将一个数的所有位向左移动指定的位数,右侧补0。

a << 2 = 0b10011000

此操作将变量 a 的所有位向左移动 2 位,右侧补 0。

6、右移(>>):将一个数的所有位向右移动指定的位数,左侧补0或补符号位(取决于所需的移位操作)。

b >> 3 = 0b00011001

此操作将变量 b 的所有位向右移动 3 位,左侧补 0。

三、组合位操作

1、把变量的某位清零,其他位不变

unsigned char var = 0xAF; // 假设变量名为 var,初始值为 0xAFvar &= ~(1 << bitIndex);
  • bitIndex是需要清零的位的索引,从右往左数,最低位索引为 0。
  • 1 << bitIndex将数字 1 的二进制表示向左移动bitIndex位,得到一个只有指定位为 1 的数值。
  • ~(1 << bitIndex)对移位后的结果取反,得到一个只有指定位为 0 的数值。
  • var &= ~(1 << bitIndex)执行按位与操作,将变量var与取反后的结果进行按位与运算,并将最终的结果赋值给var

这样操作后,变量 var 指定位被清零,其他位保持不变。

示例:

//定义一个变量 a = 1001 1111 b (二进制数)unsigned char a = 0x9f;//对 bit2 清零a &= ~(1<<2);/*bit从0开始计数,bit2为从左向右起第三个数先确定我们要得到的值为1001 1011在二进制中,数字 1 表示为 0000 0001(共 8 位),通过左移 2 位,我们可以得到 0000 0100。这里的符号 << 表示左移运算,就相当于在二进制数的右侧补充 0。括号中的 1 左移两位,(1<<2) 得二进制数: 0000 0100 b按位取反,~(1<<2) 得 1111 1011 ba 中原来的值为二进制数: a = 1001 1111 b所得的数与 a 作“&”运算,a = (1001 1111 b)&(1111 1011 b)经过运算后,a 的值 a=1001 1011 b*/

2、把变量的某几个连续位清零

假设要清零变量的第n位到第m位(n<m),可以先构造一个掩码,该掩码的第n位到第m位为0,其他位为1,然后将变量与该掩码进行按位与运算即可。

void clearBits(int& var, int n, int m) {int mask = ((1 << (m - n + 1)) - 1) << n; // 构造掩码var &= ~mask; // 按位与运算清零}

其中,1 << (m - n + 1)表示将1左移m-n+1位,即构造一个二进制数的最高位为1,其他位为0的掩码。然后再将其减1,得到一个二进制数的最高位到第n位为1,第n-1位到第0位为0的掩码。最后将该掩码左移n位,即得到一个二进制数的第n位到第m位为0,其他位为1的掩码。

示例:

//定义一个变量 a = 1001 1111 b (二进制数)unsigned char a = 0x9f;/*若把 a 中的二进制位分成 2 个一组即 bit0、bit1 为第 0 组,bit2、bit3 为第 1 组,bit4、bit5 为第 2 组,bit6、bit7 为第 3 组要对第 1 组的 bit2、bit3 清零*/a &= ~(3<<2*1);/*3 = 0000 0011 b括号中的 3 左移两位,(3<<2*1) 得二进制数: 0000 1100 b按位取反,~(3<<2*1) 得 1111 0011 ba 中原来的值为二进制数: a = 1001 1111 b所得的数与 a 作”位与&”运算,a = (1001 1111 b)&(1111 0011 b),经过运算后,a 的值 a=1001 0011 ba 的第 1 组的 bit2、bit3 被清零,而其它位不变。*//*上述 (~(3<<2*1)) 中的 1 即为组编号; 如清零第 3 组 bit、bit7 此处应为 3括号中的 2 为每组的位数,每组有 2 个二进制位; 若分成 4 个一组,此处即为 4括号中的 3是组内所有位都为 1 时的值; 若分成 4 个一组,此处即为二进制数“1111 b”例如对第 2 组 bit4、bit5 清零a &= ~(3<<2*2);*/

3、对变量的某几位进行赋值

假设我们有一个整数变量 num,要对第 n 位到第 m 位(包括 nm)进行赋值为 value,可以使用位运算符进行操作。首先,需要将这几位清零,然后将 value 的相应位设置为所需的值。

num = (num & ~((1 << (m+1)) - 1)) | (value << n)

示例:

//a = 1000 0011 b//此时对清零后的第 2 组 bit4、bit5 设置成二进制数“01 b ”a |= (1<<2*2);//a = 1001 0011 b,成功设置了第 2 组的值,其它组不变

4、对变量的某位取反

可以使用位异或运算符(^)来对整数类型的变量的某位进行取反操作。假设我们有一个整数变量 num,要对第 n 位进行取反,可以使用如下表达式:

num = num ^ (1 << n)

<< 是左移运算符,将 1 左移 n 位,然后与 num 进行异或运算,即可对第 n 位进行取反。

示例:

//a= 1001 0011 b//把 bit6 取反,其它位不变a=(1<<6);//a = 1101 0011 b