目录
1.移位操作符
<<左移操作符:左边抛弃、右边补0
>>右移操作符:分两种情况
1:逻辑移位:左边用0填充,右边丢弃
2:算术移位:左边用原该值的符号位填充,右边丢弃
注:移位操作符的操作数只能是整数,移位操作符是对2进制位进行操作移动
给出以下代码示例:
#include<stdio.h>
int main(void)
{
//a的二进制原码 反码 补码:
//00000000000000000000000000001010
int a = 10;
// <<:左边抛弃,右边补0
//00000000000000000000000000010100
//所以b=20
int b = a <<1;
// >>:左边用原来该值的符号位填充,右边丢弃
//00000000000000000000000000000101
//所以c=5
int c = a >> 1;
printf("%d\n%d\n%d", a, b, c);
return 0;
}
a的二进制原码 反码 补码:00000000000000000000000000001010
<<:左边抛弃,右边补0
00000000000000000000000000010100
所以b=20
>>:左边用原来该值的符号位填充,右边丢弃
00000000000000000000000000000101
所以c=5
我们来运行一下程序
int num = 10;
num>>-1;//error
2.位操作符
#include <stdio.h>
int main(void)
{
int num1 = 1;
//00000000000000000000000000000001
int num2 = 2;
//00000000000000000000000000000010
printf("%d\n",num1 & num2);
//00000000000000000000000000000000
printf("%d\n", num1 | num2);
//00000000000000000000000000000011
printf("%d\n", num1 ^ num2);
//00000000000000000000000000000011
return 0;
}
num1的补码为:00000000000000000000000000000001
num2的补码为:00000000000000000000000000000010
因此printf打印的结果应该为:
0
3
3
运行结果:
接下来又一道面试题: 不使用临时变量交换两个数的值
对于交换两个变量我们最常用的思路就是创建一个临时变量
int tmp=a;
a=b;
b=tmp;
即可完成交换
但本题有限制要求,不能创建临时变量
思路2:
int a=3,b=7;
a=a+b;//10
b=a-b;//3
a=a-b;//7
但这个也有缺陷,那就是当数字很大的时候int会爆掉
思路3:
利用按位异或操作符
先看一个例子:
#include<stdio.h>
int main(void)
{
int a = 10;
//00000000000000000000000000001010
int b = 3;
//00000000000000000000000000000011
int c = a ^ a;
//00000000000000000000000000001010
//00000000000000000000000000001010
//异或结果:00000000000000000000000000000000
int d = a ^ a ^ b;
//a^a的结果为0 0^b结果为b
int e = a ^ b ^ a;
//a^b 00000000000000000000000000001001
//再^a得到00000000000000000000000000000011
//发现结果还是为3
printf("%d\n%d\n%d\n", c, d, e);
return 0;
}
输出结果为:
由此可以得到:异或运算符支持交换律
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;//a^b^b = a
a = a^b;//a^a^b = b
printf("a = %d b = %d\n", a, b);
return 0;
}
我们再看一道面试题:求一个整数存储在内存中的二进制中1的个数。
#include <stdio.h>
int main()
{
unsigned int num = -10;
int count = 0;//计数
while (num)
{
if (num % 2 == 1)
count++;
num = num / 2;
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
这里num的数据类型使用unsigned int 的原因为当num为负数的时候就算不出来了
方法二:
利用按位与操作符
当我们要判断这个二进制位的某一位是否为1,可以构造出一个对应位上为1,其他位全为0的二进制序列,利用按位与操作符的性质(&),都为1才为1可以得到该位置是否为1
那么如何构造呢?,我们知道1的二进制序列为:00000000000000000000000000000001,当我们想要将这个1设置在固定的某一项的时候,可以将其二进制序列进行左移(左边抛弃,右边补0)
那么代码可以这样写:
#include<stdio.h>
int main(void)
{
int num = 10,i=0,count=0;
for (int i = 0; i < 32; i++)
{
if (num & (1 << i))
{
count++;
}
}
printf("二进制中1的个数为:%d", count);
return 0;
}
但这样写的代码会有一个问题,那就是对于所有的二进制数都要遍历32次,比较麻烦
方法3:
#include <stdio.h>
int main()
{
int num = 10;
int i = 0;
int count = 0;//计数
while (num)
{
count++;
num = num & (num - 1);
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
//num:
//00000000000000000000000000001010
//num-1:
//00000000000000000000000000001001
//num&num-1:
//00000000000000000000000000001000
//num:
//00000000000000000000000000001000
//num-1:
//00000000000000000000000000000111
//num&num-1:
//00000000000000000000000000000000
每一次num&num-1都会借走一个1,当num为0的时候结束循环
运行结果:
练习题:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
#include<stdio.h>
int main(void)
{
int n = -1;
printf("奇数位:");
for (int i = 30; i >= 0; i -= 2)
{
printf("%d ", (n >> i) & 1);
}
printf("\n");
printf("偶数位:");
for (int i = 31; i >= 1; i -= 2)
{
printf("%d ", (n >> i) & 1);
}
return 0;
}
练习题:
编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
输入例子:
1999 2299
输出例子:7
这题的思路很明显,可以用位操作符^(按位异或)(相同为0,相异位1)
那么只需要计算1999^2299的结果有多少个1就行了
代码:
#include<stdio.h>
int main(void)
{
int a = 1999, b = 2299;
int tmp = a ^ b,count=0;
while (tmp)
{
tmp = tmp & (tmp - 1);
count++;
}
printf("%d", count);
return 0;
}