这篇博客主要介绍移位操作符与位操作符,在介绍这两个操作符之前,先简要讲一下理解这两个操作符需要的基础知识——也就是二进制和原反补码!
1.进制
进制是人为规定的一种进位方法,有很多种。比如,我们日常使用的数字即为十进制。十进制逢十进一,所有数字均由0-9组成。八进制逢八进一,所有数字均由0-7组成。二进制逢二进一,所有数字均由0、1组成。十六进制逢十六进一,所有数字由0-9,a-f组成。
在日常生活中也有很多进制的例子,例如星期,逢七进一,七进制;月份逢十二进一,十二进制;小时数,逢二十四进一,二十四进制。
而计算机是一个二进制系统,数据在计算机中以二进制的形式储存。
2.整数的二进制表示
整数的二进制表示有三种,分别为原码、补码与反码。正整数的原码、补码与反码相同,而负整数的原码、补码与反码是需要计算的。
整数在内存中一般以int类型存储,int类型数据在内存中占四个字节,32个比特位,即32个二进制位。
原码是根据整数直接写出的序列。值得注意的是,二进制序列的最高位是符号位,0代表是正数,1代表是负数。
例如:7。
7的原码很简单可以写出:00000000 00000000 00000000 00000111
由于7为正整数,7的反码、补码与原码相同。
例如:-7
由于-7为负数,因此-7二进制序列的符号位为1,即二进制序列的最高位为1。
因此,-7的原码为:10000000 00000000 00000000 00000111
负数的补码与反码是需要计算的。
反码:原码的符号位不变,其他位按位取反即为反码。
按位取反:每一个二进制位,原值为0,则改为1;原值为1,则改为0。
因此,-7的反码:11111111 11111111 11111111 11111000
补码:反码加1即为补码。
因此,-7的补码:11111111 11111111 11111111 11111001
而整数在内存中是以补码存储的!!!
至此,基础的小知识就说完啦!
3.移位操作符
移位操作符移的就是我们上文所讲的二进制位!
移位操作符分为(<<)左移操作符和(>>)右移操作符。
注意:1.移位操作符的操作对象只能为整数!
2.对于移位操作符,不要移动负数位(eg. int b=a>>-1),这个是标准未定义的,不同的编译器下可能会产生不同的结果。
1.左移操作符
左移操作符:左边丢弃,右边补0(操作对象为在内存中存储的补码)。
例如,
int main()
{
int a = 7;
int b = a << 1;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
a左移1位赋值给b,即下图:
因此,代码输出结果为:
a左移一位后,a本身不会发生变化,只会将左移一位后所得的值赋值给b。
左移之后,之前的二进制码均高了一位。因此,<<1其实有乘二的效果!
但它与乘2不同的是:<<1不会出现溢出现象,而某一个数字直接乘2所得的值可能会超过int型的范围,产生溢出现象!
2.右移操作符
右移操作符有两种移位规则,分别为逻辑移位与算术移位。
逻辑移位:左边用0填充,右边丢弃。
算术移位:左边用该原值的符号位填充,右边丢弃。
通常编译器中采用的是算术移位!
右移一位相当于将这个数除以2!
因此,-7右移一位后补码为:11111111 11111111 11111111 11111100
补码减1后得反码,即:11111111 11111111 11111111 11111011
除符号位按位取反得原码,即:10000000 00000000 00000000 00000100
因此,-7右移一位后得-4。
代码及输出结果为:
同样,a右移一位后,a本身不会发生变化,只会将右移一位后所得的值赋值给b。
4.位操作符
位操作符中的位同样为二进制位!同时,位操作符操作数必须为整数!
位操作符有以下三种:
&:按位与
|:按位或
^:按位异或
1.按位与&
两数的补码对应二进制位均为1时,为1;有0时,则为0。
2.按位或
两数的补码对应二进制位均为0时,为0;有1时,则为1。
3.按位异或
两数的补码对应二进制位相同为0,相异为1。
按位异或有如下特点:
1. a^a=0;
2. 0^a=a;
3.按位异或运算支持交换律。例如:3^3^4=3^4^3=4。
4.按位异或应用
下面说明了按位异或的两个基本小应用。
1.翻转特定的二进制位
例如:
若想将a的第二位与第四位翻转,可以将a与00001010(前三个字节省略了)进行按位异或。
2.在不使用临时变量的情况下,交换两个变量的值。
例如:
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前,a=%d,b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后,a=%d,b=%d\n", a, b);
return 0;
}
a首先被赋值为3^5,b=a^b=3^5^5=3,a=a^3=3^5^3=5,至此完成两个变量值的交换。
5.位操作符与移位操作符的几个应用
1.统计二进制位中1的个数
//统计二进制中1的个数
#include <stdio.h>
int main()
{
int num = 0;
int i = 0;
int sum = 0;
printf("请输入一个数字:->");
scanf("%d", &num);
for (i = 0; i < 32; i++)
{
sum += (num >> i) & 1;
}
printf("%d中二进制中1的个数为%d\n",num,sum);
return 0;
}
2.打印二进制位的奇数位和偶数位
#include <stdio.h>
int main()
{
int num = 0;
int i = 0;
printf("请输入一个整数:->");
scanf("%d", &num);
for (i = 31; i >=0; i -= 2)
{
printf("%d", (num>>i) & 1);
}
printf("\n");
for (i = 30; i>=0; i -= 2)
{
printf("%d", (num >> i) & 1);
}
printf("\n");
return 0;
}
3.求两个数二进制位不同的个数
//求两个数二进制中不同位的个数
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int ret = 0;
int i = 0;
int sum = 0;
printf("请输入两个整数:->");
scanf("%d %d", &num1, &num2);
ret = num1 ^ num2;
for (i = 1; i <= 32; i++)
{
sum += ret & 1;
ret >>= 1;
}
printf("%d", sum);
return 0;
}