位操作符的概念:
位操作符有三种:&(按位与)、|(按位或)、^(按位异或)。
需要注意的是:位操作符的操作数为整数,且具体实现操作的是两个整数的补码。
原码、补码、反码的概念:
(1)有符号数的原码、补码、反码分为符号位和数值位两部分,符号位为首位二进制数,0表示正数,1表示负数。
(2)正整数的原码、补码、反码相同。
(3)负整数的原码为符号位1与对应的数值位组成;反码为原码的符号位不变,其它位次按位取反(0变为1,1变为0);补码为反码+1 。
一、&(按位与):两个整数的补码对应的二进制位有0则为0,两个同时为1才为1,得到的数仍为补码。
举个栗子:
//&(按位与)有0为0,同为1为1 int a = 1;// 补码为:00000000000000000000000000000001 int b = 2;// 补码为:00000000000000000000000000000010 int c = a & b;//补码为:00000000000000000000000000000000 //所以c的值为0
二、|(按位或):两个整数的补码对应的二进制位有1则为1,两个同时为0才为0,得到的数仍为补码。
举个栗子:
//|(按位或)有1为1,同为0为0 int a = 1;// 补码为:00000000000000000000000000000001 int b = 2;// 补码为:00000000000000000000000000000010 int c = a | b;//补码为:00000000000000000000000000000011 //所以c的值为3
三、^(按位异或):两个整数的补码对应的二进制位相同为0,相异为1,得到的数仍为补码。
举个栗子:
//^(按位异或)相同为0,相异为1 int a = 1;// 补码为:00000000000000000000000000000001 int b = 2;// 补码为:00000000000000000000000000000010 int c = a ^ b;//补码为:00000000000000000000000000000011 //所以c的值为3
位操作符的应用:
一、&(按位与)的应用:
(1)取某个二进制数的末尾:
int a = 1;//补码:00000000000000000000000000000001 int tmp1 = a & 1;//此时tmp1的值为1 int b = 2;//补码:00000000000000000000000000000010 int tmp2 = a & 1;//此时tmp2的值为0
比如某些题目要求你按位输出某个数的二进制位,那么就可以搭配移位操作符来实现:
int main() { int a = 1; int i = 0; for (i = 0; i < 32; i++) { printf("%d", a & 1); a >>= 1; } return 0; }
(2)令某个二进制数最右面的1消失:
int n = 1;//n的补码:00000000000000000000000000000001 n = n & (n - 1);(n-1)的补码:00000000000000000000000000000000 //结果n的补码:00000000000000000000000000000000
二、^(按位异或)的应用:
一道面试题:不创建临时变量,交换两个数。
一般想要交换两个数是这样操作的:
tmp = num2; num2 = num1; num1 = tmp;
如果创建临时变量的话其实还有另一种方法:
num1 = num1 + num2; num2 = num1 - num2; num1 = num1 - num2;
那么如何利用^ (按位异或)来实现变量交换呢,其实^(按位异或)的运算规则满足交换律,比如:
a ^ a = 0; a ^ 0 = a; a ^ b ^ a = b;//先运算a ^ a = 0;在运算0 ^ b = b; //可以理解为(a ^ a) ^ b = b;
由此我们可以知道:
a = a ^ b; b = a ^ b; a = a ^ b;
画一张图:
这种方法很巧妙,但是实用性并不高,它的效率甚至不如创建临时变量高,但是它可以让你更好的理解位操作符可能会实现一些零你意想不到的操作。