一.移位操作符

​1.右移操作符(符号: >>  ,移动的是二进制位)分为算术右移,逻辑右移

                            算术右移:右边丢弃,左边补原符号位

                            逻辑右移:右边丢弃,左边补0

注意:

不同编译器所代表的右移操作符的含义不同,即可能是算术右移,也可能是逻辑右移

举个例子:

#include<stdio.h>
int main()
{
int a=16;
//16转化为2进制 00000000000000000000000000010000(共32位)
int b=a>>1;
//所以变成00000000000000000000000000001000(b=8)
printf("%d",b);
return 0;
}

打印结果如下

c语言操作符(超详细,新手向)_c语言


2.左移操作符:左边抛弃,右边补0


#include<stdio.h>
int main()
{
int a=5;
//16转化为2进制 00000000000000000000000000000101(共32位)
int b=a<<1;
//所以变成00000000000000000000000000001010(b=10)
printf("%d",b);
return 0;
}

结果如下图

c语言操作符(超详细,新手向)_c语言_02

注意:上述情况只适用于正数,负数情况有所不同

​在讲负数之前先引入三个名称:原码,,反码,补码(整数的二进制表示)。

      由于储存到内存的是补码,所以移位操作符都是操作补码的二进制。将整数转化的二进制表示的数为原码,应转化为补码再使用移位操作符(正数的特别在于:原码,反码,补码相同,所以在原码上操作等同于在补码上操作),所以若整数为负数,应先将原码转化为补码再进行操作。


那负数的原码,反码,补码应如何转化呢?

负数的原码就是符号位加数字(符号位即二进制第一个位置,1位负数,0为正数)

反码就是原码除符号位的部分全部取反

补码就是反码加一

举个例子,-1

//10000000000000000000000000000001        原码

//111111111111111111111111111111111110        反码

//111111111111111111111111111111111111         补码

int main()
{
int a = -1;
int b = a >> 1;//由于右移一位后符号位补1(即负号),所以补码仍是11111111111111111111111111111111
//所以仍为-1
printf("%d\n", b);
return 0;
}

运行结果如下c语言操作符(超详细,新手向)_c语言_03


                                                    注意:

   移位操作符不要移动负数位,这个标准未定义,且移位操作符只能作用与整数

二​.位操作符

​&  按位与   (一个0则为0,两个1才为1)

|   按位或   (有1则为1,都为0才为0)

^  按位异或(相同为0,相异为1)

注意:操作数必须是整数


#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = a & b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000001
printf("%d", c);
return 0;
}

输出结果为:1

c语言操作符(超详细,新手向)_c语言_04


#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = a | b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000111
printf("%d", c);
return 0;
}

输出结果为:7

c语言操作符(超详细,新手向)_c语言_05

#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = a ^ b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000110
printf("%d", c);
return 0;
}

输出结果为:6

c语言操作符(超详细,新手向)_c语言_06


一道笔试题:

交换两个int变量的值,不能使用第三个变量,即a=3,b=5,交换之后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=3c语言操作符(超详细,新手向)_c语言_07


第二种解法:异或的方法

#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

c语言操作符(超详细,新手向)_c语言_08


练习:求一个整数储存在内存中的二进制中1的个数

(思路:一个整形是4个字节,32bit,利用for循环将num的补码与1的补码比较,由于1的补码只有最后一位为1即保证了只有num的补码最后一位才是比较的有效值,最后判断补码的最后一位是否为1,若为1则为真,则1==1,符合条件,count++,如此循环。)

#include<stdio.h>
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的补码
}