C语言中基本的位操作符有 左移、右移、按位与、按位或、按位异或、取反)
我们用表格先归总一下
名称 | 符号 | 运算规则 |
---|---|---|
左移 | << | 高位丢弃,低位补0 |
右移 | >> | 对无符号数,高位补0. 对有符号数,算数右移高位补符号位,逻辑右移高位补0 |
按位与 | & | 两位同为“1”,结果才为“1”,否则为0 |
按位或 | l | 两位只要有一个“1”,结果就为“1”,否则为0 |
按位异或 | ^ | 两位 同“0”异“1” |
取反 | ~ | “1”变“0”,“0”变“1” |
**1.左移 << **
int num = 10;
num = num << 1;
printf("%d",num);
所以左移几位就是原数乘2的n次方
**2.右移 >> **
右移运算分两种(因为数在内存中以补码形式存储的):
int num1 = 10; //二进制 00000000 00000000 00000000 00001010
num1 = num1 >> 1; //右移1位 00000000 00000000 00000000 00000101
int num2 = -10; //二进制 11111111 11111111 11111111 11110110
num2 = num2 >> 1; //右移1位 11111111 11111111 11111111 11111011
printf("%d %d\n", num1,num2); //num1 = 5 ,num2 = -5
ps:对于移位运算符,不要移动负数位,这个是标准未定义的
例:
int num = 10;
num>>-1;//error
**3.按位与 & **
参加运算的两个数,按二进制位进行“与”运算:
0&0=0; 0&1=0; 1&0=0; 1&1=1;
例:
int num1 = 1; //二进制 0001
int num2 = 2; //二进制 0010
int num = num1 & num2; //按位与运算 0000
printf("%d\n", num); //num = 0
**4.按位或 | **
参加运算的两个数,按二进制位进行“或”运算:
0|0=0; 0|1=1; 1|0=1; 1|1=1;
例:
int num1 = 1; //二进制 0001
int num2 = 2; //二进制 0010
int num = num1 | num2; //按位或运算 0011
printf("%d\n", num); //num = 3
**5.按位异或 ^ **
参加运算的两个数,按二进制位进行“异或”运算:
0^0=0; 0^1=1; 1^0=1; 1^1=0;
按位异或有几个重要性质:
例:
1、交换律 a ^ b = b ^ a
2、结合律 (a^b) ^ c = a^ (b^c)
3、对于任何数x,都有x ^ x = 0 ,x ^ 0 = x
int num1 = 1; //二进制 0001
int num2 = 2; //二进制 0010
int num = num1 ^ num2; //按位异或运算 0011
printf("%d\n", num); //num = 3
ps:以上三个位操作符(按位与、按位或、按位异或)的操作数必须是整数
**6.取反 ~ **
对一个数的二进制按位取反:1变0,0变1
int num = 1; //二进制 00000000 00000000 00000000 00000001
num = ~num; //二进制 11111111 11111111 11111111 11111110
printf("%d\n", num); //取反运算 num = -2
1.不创建临时变量(第三个变量),实现两个数的交换(一道面试题)
#include
int main()
{
int a = 1; //0001
int b = 2; //0010
a = a^b; //0001 ^ 0010 = 0011
b = a^b; //0011 ^ 0010 = 0001
a = a^b; //0011 ^ 0001 = 0010
printf("a = %d b = %d\n", a, b); //a = 2 b = 1
return 0;
}
理解的时可以参照上面列出的按位异或的几个性质
2. 求一个整数存储在内存中的二进制中1的个数
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
for(i=0; i<32; i++)
{
if( ((num>>i)&1) == 1 )
count++;
}
printf("二进制中1的个数 = %d\n",count);
return 0;
}
思考一下还有没有更简洁的做法?(上面这种做法必须要循环32次)
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
while(num)
{
count++;
num = num&(num-1);
}
printf("二进制中1的个数 = %d\n",count);
return 0;
}
3.给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素(leetcode 136)。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int val = 0;
for(auto e : nums)
{
val ^= e;
}
return val;
}
};