浅谈C语言中的移位操作符

2023-12-18 16:30:31

参考两篇博客(浅谈操作符(1)-CSDN博客?浅谈操作符(2)-CSDN博客

一.右移,左移操作符>>和<<

(1).左移操作符<<
????????众所周知,电脑储存数据是以二进制的方式来储存的,在c语言中也不例外。右移和左移操作符,顾名思义:就是对操作数进行左右移动的,但它却有它独一无二的特点——移动的是二进制位。让我们来举个例子:5的二进制表示是101,5是整型,在内存中占4个字节,相当于32位比特位,所以说将其写完整:
00000000000000000000000000000101(5的二进制位的完整表达式)这是5的原码,我们知道当一个数是正数时,它的反码,补码都是一样的,所以说5的反码和补码都是00000000000000000000000000000101(反码,补码都一样),然后我们已知在内存中存储的是数的补码(埋下伏笔先)现在我们对它左移1位:
(左移前) ? ? ? ?00000000000000000000000000000101
(执行左移) ?00000000000000000000000000000101 ? ? ? ?(我们可以看到最左边的0被移出去了(32位,只有32位,不能多占了)),这时,右边差一位啊,不能空着,所以说自动会补0
(左移补0) ? ? 000000000000000000000000000001010 ? ? ? ?这个时候,对5执行左移1位之后,得到的值是10,相当于5<<1等于10,让我们用代码来实验一下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = 5;//定义a=5
	a = a << 1;//a左移一位
	printf("%d\n", a);//输出a
	return 0;
}

?????????显然,左移操作符就是这样,而且左移的位数(右移也可以)可以由自己来确定,可以移动多位,让我们再来一次:

? ? ? ? ? ? ? ? 00000000000000000000000000000101 ? ? ? ?(还是5,还没有移动)

? ? ? 00000000000000000000000000000101 ? ? ? ? ? ? ? ? ?(我们给它左移五位)

? ? ? ? ? ? ? ? 00000000000000000000000010100000 ? ? ? ?(给它移动后补0),现在的值就已经变成了160了(32+128),用代码来实验一下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = 5;
	a = a << 5;//左移5位
	printf("%d\n", a);
	return 0;
}

这就是正数的左移操作符的使用方法了,看似还是十分简单的——因为正数的原码、反码、补码都相等,相当于只需要知道其原码,就可以知道反码和补码了,十分的方便。但我们生活中大抵是少不了负数(非正数)的存在,负数的移动相对正数而言更加的麻烦,让我娓娓道来。

? ? ? ? 我们还是先举个例子,我们来个-5,我们将-5用二进制表示出来:

? ? ? ? 10000000000000000000000000000101 ? ? ? ?(最前面的1是符号,二进制首位1为负数,0为正数),这是它的原码,让我们求一下它的反码——首位(符号位不变),其它位按位取反:

11111111111111111111111111111010(这就是-5的反码表示),补码就是反码+1,那就是:

11111111111111111111111111111011,这便是-5的补码了,我们还是给它左移一位,来浅看一下:

? ? ? ? ? ? ? ? ? ? ? ? 11111111111111111111111111111011 ? ? ? ?(左移前)

? ? ? ? ? ? ? ? ? ? ? 11111111111111111111111111111011 ? ? ? ? ?(左移一位)

? ? ? ? ? ? ? ? ? ? ? ? 11111111111111111111111111110110 ? ? ? ?(完成了左移并补0)

? ? ? ? 看到这里,你也许会很惊讶——难道-5只是移动了一位,就变得这么大了吗?我要输出它,一个整型还不够?其实不是这样的,虽然在内存中存储的是数的补码,但是输出的却是数的原码,所以说我们先求出了补码并移动了还不够,我们还需要将移动后的数字来再求它的原码之后得到的数字才是真正的负数左移的值,让我们来求其原码:(补码先-1,再按位取反就是其原码了。)

? ? ? ? ? ? ? ? ? ? ? ? 11111111111111111111111111110101(-1)

? ? ? ? ? ? ? ? ? ? ? ? 10000000000000000000000000001010(按位取反)这便是-5左移1位后的原码了,它的值是-10,让我们验证一下:
?

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = -5;
	a = a << 1;
	printf("%d\n", a);
	return 0;
}

总结
? ? ? ? 左移操作符相当于将数的二进制的补码向左移动一位,然后在末尾补0;正数的原码、反码、补码都是一样的,所以说相对简单;但值得一提的是:负数的原码、补码不同,需要注意这一点;并且更重要的一点是——移动的是数的补码,但是真正输出的却是数的原码,所以说在移位负数时,是先算出其补码,再移动,再根据补码算出其移动后的原码,再进行输出的。

(2)右移操作符>>

顾名思义,右移操作符是将数的二进制位进行向右移动,参考一下左移操作符的移动方式,我们就能很轻松的得到右移操作符的移动规则,我们举个例子来讲解一下:
? ? ? ? 假如说,有一个数字5,它的二进制表达是00000000000000000000000000000101,因为它是正数,所以说其原码、反码、补码都相同,所以说它的补码也是00000000000000000000000000000101,让我们对其进行右移1位:
? ? ? ? ? ? ? ? ? ? ? ? 00000000000000000000000000000101(右移前)
? ? ? ? ? ? ? ? ? ? ? ? ? 00000000000000000000000000000101(对其右移1位)
? ? ? ? ? ? ? ? ? ? ? ? 00000000000000000000000000000010(对其补0)
? ? ? ? 现在计算,5右移一位就变成了2,让我们来验证一下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = 5;
	a=a >> 1;
	printf("%d\n", a);
	return 0;
}

????????发现确实右移就是像我们想的那样,和左移类似的移动方法?将数的二进制补码向右移动任意位数,然后在前面根据符号来补0或者1,然后再转换成其原码,进行输出。
? ? ? ? 既然已经为大家详细的讲解了负数的左移方法,我就不再赘述负数的右移方法了,总之记住一句话:负数要先从原码转换为其补码,再进行移动,移动后再转换为移动后的原码,再进行输出。记住这个,负数的移动就能够掌握。
?

?

文章来源:https://blog.csdn.net/Aishangyuwen/article/details/134970202
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。