目录
一、什么是位操作
二、位操作有哪些
三、组合位操作
一、什么是位操作
位操作是指直接对二进制数的位进行操作的一类运算。在计算机中,数据以二进制形式存储和表示,在某些情况下需要对二进制数的位进行特定操作,这就用到了位操作。
位操作通常用于优化代码、实现位级别的标志操作、提取和设置二进制数中的特定位等场景。但需要注意,位操作对于代码的可读性和可维护性可能有一定的影响,应谨慎使用,并确保操作的正确性和逻辑清晰性。
二、位操作有哪些
假设有两个无符号字符变量 a
和 b
,它们的二进制表示分别为:
a = 0b10100110b = 0b11001100
常见的位操作包括:
1、按位与(&):将两个数的每一位进行与运算,只有当两个位都为1时,结果才为1,否则为0。
a & b = 0b10000100
此操作将 a
和 b
的每一位进行与运算,只有当两个位都为 1 时,结果位才为 1,否则为 0。
2、按位或(|):将两个数的每一位进行或运算,只有当两个位都为0时,结果才为0,否则为1。
a | b = 0b11101110
此操作将 a
和 b
的每一位进行或运算,只有当两个位都为 0 时,结果位才为 0,否则为 1。
3、按位异或(^):将两个数的每一位进行异或运算,当两个位相同(都为0或都为1)时,结果为0,否则为1。
a ^ b = 0b01101010
此操作将 a
和 b
的每一位进行异或运算,当两个位相同(都为 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
位(包括 n
和 m
)进行赋值为 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