考虑如下情形,对一个无符号数num
的指定位进行取反。
假设对num
的第3位进行取反,程序运行过程中我们并不知道num
第三位的取值情况,所以需要分情况讨论,很容易会想到如下实现方法:
unsigned char num;
if(num&0x08) // num的第3位为1
{
num &= ~0x08; //num = num&(~ 0x08);
}
else // num的第3位为1
{
num |= 0x08; //num = num | 0x08;
}
如果要把上面是假设推广到一般情况,由调用者指定要取反的位。为此我们引入一个变量bitNum
,用于指定要取反的位,那么我们将得到如下函数:
unsigned char num;
/*
*┌───────────────────────────────────────┐
*│ Description : main function
*│ Parameter : bitNum -位序号
*│ Return : None
*│ Author : 羽墨志
*└───────────────────────────────────────┘
*/
void reverseBit(unsigned char bitNum)
{
if(num&(0x01<<bitNum))
{
//num = &(~(0x01<<bitNum));
num &= ~(0x01<<bitNum);
}
else
{
//num = num | (0x01<<bitNum);
num |= 0x01<<bitNum;
}
}
【注】这里之所以不直接num
进行赋值,是因为直接赋值不仅改变了目标位的值,同时还可能改变了其他位的值,这是不被允许的。num &= mask;
能够确保不改变其他位的前提下把num
的对应位变为0
,而num |= mask;
能够确保不改变其他位的前提下把num
的对应位变为1
。
虽然实现了功能,总觉得还是不够简洁明了。上面的实现方法核心是位与和位或操作,先通过移位(这里是左移)操作定位到对应的位,而后通过位与操作判断对应位的取值,最后通过位与和位或操作改变对应位的值。
异或运算具有“相同为0,不同为1”的特点,与0
异或的结果保持不变,与1
异或的结果x相当于取非操作。利用这一特点我们可以得到如下实现:
unsigned char num;
/*
*┌───────────────────────────────────────┐
*│ Description : main function
*│ Parameter : bitNum -位序号
*│ Return : None
*│ Author : 羽墨志
*└───────────────────────────────────────┘
*/
void reverseBit(unsigned char bitNum)
{
// num = num ^ (0x01<<bitNum);
num ^= 0x01<<bitNum;
}
这样一来就省去了取值判断步骤,大大精简了代码,提高了程序的运行效率。
位运算总结
-
按位与
&
:同1为1,否则为0。&
0
1
0
0 & 0 = 0;
0 & 1 = 0;
1
1 & 0 = 0;
1 & 1 = 1;
-
按位或
|
:同0
为0
,否则为1
。&
0
1
0
0 | 0 = 0;
0 | 1 = 1;
1
1 | 0 = 1;
1 | 1 = 1;
-
按位异或
^
:相同为0
,否则为1
。^
0
1
0
0 ^ 0 = 0;
0 ^ 1 = 1;
1
1 ^ 0 = 1;
1^ 1 = 0;
-
按位取反
~
:1
变0
,0
变1
。~
0
1
~1 = 0;
~0 = 1;
-
移位运算: 将整型或字符型数据作为二进位信息串整体向左或向右移动若干位。
- 左移
<<
:左移运算将一个位串信息向左移指定的位 。 - 右移
>>
:右移运算将一个位串信息向右移指定的位 。
【注】
- 对于无符号数:
- 左移时,右端空出的位用
0
补充,左端移出的位的信息被丢弃; - 右移时,左端空出的位用
0
补充,右端移出的位的信息被丢弃。
- 左移时,右端空出的位用
- 对于有符号数:
- 对于正整数(符号位为
0
),右移时,左端空出的位也用0
补充; - 对于负整数(符号位为
1
),右移时,左端空出的位用0
或用1补充,取决于计算机系统。- 负数右移,左端空出的位用
0
补充的系统称为“逻辑右移”; - 负数右移,左端空出的位用
1
补充的系统称为“算术右移” 。 - 判断方法:
- 负数右移,左端空出的位用
- 在二进制数的位运算中,在信息没有因移动而丢失的情况下,每左移
1
位相当于乘以2
, 每右移1
位,相当于除以2
。
- 左移
-
运算优先级
- 取非
~
、位与&
、异或^
、位或|
的运算优先级依次降低, 其中取非~
的结合方向自右至左,且优先级高于算术运算符,其余运算符的结合方向自左向右,且优先级低于关系运算符。 - 移位运算符的优先级低于算术运算符,高于关系运算符,其结合方向是自左向右。
即运算优先级顺序为:取非运算符
~
>算术运算符>移位运算符>关系运算符>位与&
>异或^
>位或|
。 - 取非
网友评论