移位操作符与位操作符

目录

一、移位操作符

1)左移操作符—— <<

2)右移操作符—— >>

二、位操作符

1)按位与—— &

2)按位或—— |

3)按位异或—— ^

4)按位取反—— ~

三、例题

例题1.不创建临时变量,实现两个整数的交换

例题2.编写代码实现:求一个整数存储在内存中的二进制1的个数


一、移位操作符

1)左移操作符—— <<

移位规则:左边抛弃、右边补0

以一段代码来讲解:

#include <stdio.h>

int main()
{
	int num = 10;
	int n = num << 1;
	printf("n=%d\n", n);
	printf("num=%d\n", num);
	return 0;
}

首先,我们知道正数的原码、反码、补码是相同的,所以:

10的原码为:00000000 00000000 00000000 00001010

10的反码为:00000000 00000000 00000000 00001010

10的补码为:00000000 00000000 00000000 00001010

对于左移操作符(即<<),顾名思义就是向左移动x位,在上述代码中对应的x为1,根据移位规则,将补码向左移动移位,然后在后边补0,即下图所示。

由于符号位是0,整数的原码和补码是相同的,即10左移1位后的数为20。

2)右移操作符—— >>

右移运算有两种,一是逻辑右移,二是算数右移。

①逻辑右移:左边用0填充,右边丢弃

②算数右移:左边用原该值的符号位填充,右边丢弃

在不同的编译器中可能不同,不过大部分编译器都是算数右移,在VS上亦是如此。

方法与上述类似,我们再以上述的代码为例,10算数右移一位后是多少呢?答案是5,方法与上述类似,不过多赘述了。

注意:移位操作符的操作数只能是整数。

二、位操作符

位操作符与移位操作符一样都是对补码进行操作的,并且他们的操作数必须是整数。我们先看一段代码然后进行讲解。

#include <stdio.h>

int main()
{
	int m = -3;
	int n = 5;
	printf("%d\n", m & n);
	printf("%d\n", m | n);
	printf("%d\n", m ^ n);
	printf("%d\n", ~0);
	return 0;
}

1)按位与—— &

简单来说,就是两个都为1才为1,有一个为0则为0。

先来回顾一下负数的原码、反码、补码,负数的反码是在原码的基础上,除符号位外其余取反,而补码则是在反码的基础上再加1。

-3的原码为:10000000 00000000 00000000 00000011

-3的反码为:11111111 11111111 11111111 11111100

-3的补码为:11111111 11111111 11111111 11111101

5的补码为:00000000 00000000 00000000 00000101

将-3和5的补码对照来看,每个位对齐,都为1则为1,有0则为0,得到:00000000 00000000 00000000 00000101,由于为正数,其补码与原码相同,即(-3)& 5为5。

2)按位或—— |

简单来说,就是有一个为1则为1,两个都为0则是0。

-3的补码为:11111111 11111111 11111111 11111101

5的补码为:00000000 00000000 00000000 00000101

按照此规则,得到11111111 11111111 11111111 11111101,这是补码,补码取反加1可以得到原码,即10000000 00000000 00000000 00000011,即-3。

3)按位异或—— ^

简单来说,就是相同的则为0,不同的则为1。

-3的补码为:11111111 11111111 11111111 11111101

5的补码为:00000000 00000000 00000000 00000101

我们很容易得到按位异或后的补码为:11111111 11111111 11111111 11111000,其原码为10000000 00000000 00000000 00001000,即-8。

4)按位取反—— ~

每一位都依次取反,1变为0,0变为1,包括符号位。

0的补码为 00000000 00000000 00000000 00000000,按位取反后:11111111 11111111 11111111 11111111,在这个补码的基础上再取反加1得到原码:10000000 00000000 00000000 00000001,即-1。

三、例题

例题1.不创建临时变量,实现两个整数的交换

方法一:

#include <stdio.h>

int main()
{
	int a = 10;
	int b = 20;
	a = a + b;  
	b = a - b;
	a = a - b;
	printf("a=%d,b=%d\n", a, b);
	return 0;
}

方法二:用^解决。

首先我们需要知道对于一个整数a,a ^ a = 00 ^  a = a,这其实比较好理解,根据规则,相同为0,不同为1,a与a是完全相同的,所以,每一位都是0,其原码也为0,而0补码每一位都是0,对于a补码中的每一个1都是不同的,所以对于位为1,所以最后得到的补码与a的补码完全一样,所以0 ^ a = a。

#include <stdio.h>

int main()
{
	int a = 10;
	int b = 20;
	a = a ^ b;
	b = a ^ b;  //相当于b = a ^ b ^ b,而b ^ b = 0, 0 ^ a = a
	a = a ^ b; //相当于 a = a ^ b ^ a ,而 a ^ a = 0, 0 ^ b = b
	printf("a=%d,b=%d\n", a, b);
	return 0;
}

例题2.编写代码实现:求一个整数存储在内存中的二进制1的个数

方法一:

我们算十进制的123中有多少1时可以想到用123 % 10,再用123 / 10的方法,一直循环到为0,算二进制中1的个数同样也可以如此。

#include <stdio.h>

int main()
{
	int num = 10;
	int count = 0;
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("二进制中1的个数为:%d\n", count);
	return 0;
}

方法二:对于一个整数,有32位,每一位都与上1,如对应位为1则count++。

#include <stdio.h>

int main()
{
	int num = 10;
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (num & (1 << i))     //1<<i 得到00000001、 00000010...
			count++;
	}
	printf("二进制中1的个数为:%d\n", count);
	return 0;
}

方法三:

#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;
}

下图是循环的过程:

其实也很好理解,每次减1后,原来为1的那一位变为0,其后一位变为1(与十进制减法一样的道理),然后与原来数与,并改变该数(num = num&(num-1))就少了一个1,即每次循环时都少一个1,直至为0。

于此,就讲解结束啦!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值