一.移位操作符
1.右移操作符(符号: >> ,移动的是二进制位)分为算术右移,逻辑右移
算术右移:右边丢弃,左边补原符号位
逻辑右移:右边丢弃,左边补0
注意:
不同编译器所代表的右移操作符的含义不同,即可能是算术右移,也可能是逻辑右移
举个例子:
int main()
{
int a=16;
//16转化为2进制 00000000000000000000000000010000(共32位)
int b=a>>1;
//所以变成00000000000000000000000000001000(b=8)
printf("%d",b);
return 0;
}
打印结果如下
2.左移操作符:左边抛弃,右边补0
int main()
{
int a=5;
//16转化为2进制 00000000000000000000000000000101(共32位)
int b=a<<1;
//所以变成00000000000000000000000000001010(b=10)
printf("%d",b);
return 0;
}
结果如下图
注意:上述情况只适用于正数,负数情况有所不同
在讲负数之前先引入三个名称:原码,,反码,补码(整数的二进制表示)。
由于储存到内存的是补码,所以移位操作符都是操作补码的二进制。将整数转化的二进制表示的数为原码,应转化为补码再使用移位操作符(正数的特别在于:原码,反码,补码相同,所以在原码上操作等同于在补码上操作),所以若整数为负数,应先将原码转化为补码再进行操作。
那负数的原码,反码,补码应如何转化呢?
负数的原码就是符号位加数字(符号位即二进制第一个位置,1位负数,0为正数)
反码就是原码除符号位的部分全部取反
补码就是反码加一
举个例子,-1
//10000000000000000000000000000001 原码
//111111111111111111111111111111111110 反码
//111111111111111111111111111111111111 补码
int main()
{
int a = -1;
int b = a >> 1;//由于右移一位后符号位补1(即负号),所以补码仍是11111111111111111111111111111111
//所以仍为-1
printf("%d\n", b);
return 0;
}
运行结果如下
注意:
移位操作符不要移动负数位,这个标准未定义,且移位操作符只能作用与整数
二.位操作符
& 按位与 (一个0则为0,两个1才为1)
| 按位或 (有1则为1,都为0才为0)
^ 按位异或(相同为0,相异为1)
注意:操作数必须是整数
int main()
{
int a = 3;
int b = 5;
int c = a & b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000001
printf("%d", c);
return 0;
}
输出结果为:1
int main()
{
int a = 3;
int b = 5;
int c = a | b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000111
printf("%d", c);
return 0;
}
输出结果为:7
int main()
{
int a = 3;
int b = 5;
int c = a ^ b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000110
printf("%d", c);
return 0;
}
输出结果为:6
一道笔试题:
交换两个int变量的值,不能使用第三个变量,即a=3,b=5,交换之后a=5,b=3.
第一种解法:加减法
(有一定缺陷,若两个数都很大可能会溢出,导致一些二进制位的丢失)
int main()
{
int a = 3;
int b = 5;
a = a + b;
b = a - b;
a = a - b;
printf("a=%d,b=%d", a, b);
return 0;
}
运行结果:a=5,b=3
第二种解法:异或的方法
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d,b=%d", a, b);
return 0;
}
运行结果:a=5,b=3
练习:求一个整数储存在内存中的二进制中1的个数
(思路:一个整形是4个字节,32bit,利用for循环将num的补码与1的补码比较,由于1的补码只有最后一位为1即保证了只有num的补码最后一位才是比较的有效值,最后判断补码的最后一位是否为1,若为1则为真,则1==1,符合条件,count++,如此循环。)
int main()
{
int num = 0;
int count = 0;
int i = 0;
scanf("%d", &num);
for (i = 0;i < 32;i++)
{
if (1 == ((num >> i) & 1))
count++;
}
printf("%d\n", count);
return 0;
//00000000000000000000000000000011 --num的补码
//00000000000000000000000000000001 --1的补码
}