C语言左移右移操作符详解
看到过很多C语言中的移位操作相关的博文,但是这些博文之间的深度实在是差别太大了,对于初学者来说,想要弄明白移位操作并不容易,有的博文仅仅是讲了怎么进行位移,初学者可能会因此写下bug,有的博文虽然到位但只是泛泛而过,让初学者难以理解。此文章由博主查阅多处博客、课程整理,主要面向初学者,同时又不乏深度,由浅及深,助力初学者更好地掌握C语言左移右移操作符。
移位是将数值向左向右移动,对于十进制来说就是实现放大十倍和缩小十倍的效果,而对于二进制而言就是放大两倍和缩小两倍的效果。
大部分的C编译器,用移位的方法得到代码比调用乘除法子程序生成的代码效率高。
在C语言中,char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long都可以进行移位操作,而double、float、bool、long double则不可以进行移位操作。
移位操作符分为算术移位和逻辑移位:
算术移位右边丢弃,左边补上原符号位,符号位和原首位之间补0,在visual studio中进行的是算术移位;
逻辑移位,就是不考虑符号位,移位的结果只是数据所有的位数进行移位。根据移位操作的目的,左移时,低位补0,右移时,高位补0。对于有符号数而言,逻辑位移没有太大意义,如果一个负数,逻辑右移,结果就会变成正数,例如10000101=-5>>1=01000010=66。
对于无符号类型的数据,所有移位操作都是逻辑移位。
对于有符号类型的数据,依据编译器不同而选择到底采用逻辑移位还是算术移位。(所以平台不同会导致移植性问题!)本例中,Visual Studio 2019进行的是算数移位,若想达到逻辑右移的效果C语言中可以利用“((unsigned int)(-5))>>n”来达到逻辑右移的效果(这里强调一样的效果,至于原理是否相通值得深究),这样最高位就就是补0了。
1)右移
右移操作符移动的是二进制位。
我们现在定义变量a,并赋值为-1,那么它在内存里存储为10000000 00000000 00000000 00000001
进行移位操作时,是对a的补码进行移位,也就是对
11111111 11111111 11111111 11111111 进行移位
int main()
{
int a = -1;
//a为10000000 00000000 00000000 00000001
//移位时移动的是11111111 11111111 11111111 11111111
return 0;
}
接下来我们对a进行移位操作,向右移动一位
#include <stdio.h>
int main()
{
int a = -1;
int b = a>>1;
printf("%d\n",b);
return 0;
}
在进行调试后,发现得到的值仍为-1
这是因为移位时是对数值的补码进行移位,并且是进行的算术移位(上文有提到Visual Studio 2019进行的是算数移位)。
-1的补码为
11111111 11111111 11111111 11111111
右移1位可得
0111111 11111111 11111111 111111111
符号位补1
11111111 11111111 11111111 11111111
打印时还原成原码为
10000000 00000000 00000000 00000001
我们现在定义变量a,并赋值为16,对其进行向右移1位的操作
a为00000000 00000000 00000000 00010000
此时a为正数,补码与原码相同。
#include <stdio.h>
int main()
{
int a = 16;
int b = a>>1;
printf("%d\n",b);
return 0;
}
在进行调试后,在进行调试后,发现得到的值为8
我们对其移位过程进行分析:
16的补码为
00000000 00000000 00000000 00010000
右移1位可得
00000000 00000000 00000000 00001000
移位前,根据二进制转十进制法则可得a=1*2^4=16
移位后,同上法则可得a=1*2^3=8
如果再对a右移1位可以得到4,这里不再演示。
这里可以发现右移有除以2的效果,向右移几位就是除以2的几次幂
但是有符号整数向右移位运算不等同于除以2的某次幂,如(-1)/2和(-1)>>1,前者的结果一般是0,后者一般是-1,所以在C语言中,负数向右移动1位并不等同于除以2。
此外,负的偶数向右移动1位也是除以2,负的奇数向右移动1位等于此数除以2,再减1,可自行调试。
2)左移
左移相对右移更为简单,即左边丢弃,右边补0,统统进行逻辑移位。
我们现在定义变量a,并赋值为5,那么它在内存里存储为00000000 00000000 00000000 00000101
也就是要对00000000 00000000 00000000 00000101进行移位
#include <stdio.h>
int main()
{
int a = 5;
int b = a << 1;
printf("%d\n", b);
return 0;
}
经调试,可得到10
如果对5向左移2位可得到20,这里不再演示,可见左移有乘以2的效果。
如果对负数进行左移,如-1
#include <stdio.h>
int main()
{
int a = -1;
int b = a << 1;
printf("%d\n", b);
return 0;
}
经调试可得-2
但这并不意味着符号位不动,也不意味着所有的负数左移能得到乘以2的效果,上文提到过左移操作是对补码进行操作。打印时候是对原码进行打印。很多人都把左移当成是对原码左移了,所以也不是符号位不动。
是因为-1的补码中有太多的1,-1的补码为11111111 11111111 11111111 11111111,向左移动1位并不会影响到后边的1成为符号位,位数足够所以最高位仍为1。
现在对-1073741825向左移1位
#include <stdio.h>
int main()
{
int a = -1073741825;
int b = a << 1;
printf("%d\n", b);
return 0;
}
经调试发现结果为正数
这是因为
-1073741825的补码为
10111111 11111111 11111111 11111111
左移1位可得
01111111 11111111 11111111 11111110
由于符号位为0此时原码和移位过的补码相等,打印的是下边的原码
01111111 11111111 11111111 11111110
对于正数来说,虽然左移不需要考虑符号位,但也要保证位数足够,不然高位会被舍弃!这里不再演示。
上文已提到过
大部分的C编译器,用移位的方法得到代码比调用乘除法子程序生成的代码效率高。
有人倾向用移位代替乘除法,这样效率高得多。但是请注意一下数据类型,到底是几位的,左移时会不会由于位数不够而高位被舍弃?符号位会不会改变?若位数不够或符号位改变,通过移位来代替乘除法就会产生bug。
如有错误或需要补充,欢迎与博主联系和探讨。
C语言左移右移操作符详解相关推荐
- c语言左移右移运算符详解
对于负数的右移:因为负数在内存中是以补码形式存在的,所以首先根据负数的原码求出负数的补码(符号位不变,其余位按照原码取反加1),然后保证符号位不变,其余位向右移动到X位,在移动的过程中,高位补1.等移 ...
- C语言基础之操作符详解
C语言基础之操作符详解 操作符的分类 算术操作符 移位操作符 位操作符 逻辑操作符 逗号表达式 表达式求值 隐式类型转换 算术转换 操作符的属性 xwg今天就带各位大佬来了解一波C语言的操作符. 操作 ...
- C语言最全操作符详解,一文精通所有操作符!
文章目录 前言 一.除号"/" 二."%"除法取余数 三.左移操作符"<<"和右移操作符">>" ...
- C语言左移右移操作符
目录 一.整数在内存中的存储方式 1.原码,补码,反码 2.注意事项 二.操作符 1.左移操作符 2.右移操作符 先介绍整数在内存中的存储方式 一.整数在内存中的存储方式 数子的表示方法主要有原码,补 ...
- c语言智力题 操作符详解例题 数据存储 指针初阶 水仙花数 杨辉三角 逆序字符串 喝汽水问题 打印图形 猜凶手 使用指针打印数组内容 调整奇数偶数顺序 运动员猜名次
[题目名称] 下面代码的结果是:a #include <stdio.h> int i; int main() {i--; //sizeof'的返回值是无符号整型if (i > siz ...
- 【C语言】sizeof操作符详解
sizeof概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符+.-等:它并不是函数. 作用: 用于计算类型或者变量所占空间的大小(以字节为单位) 那么字节又是什么? 字节(Byte ) ...
- java 左移 返回值_java左移右移运算符详解
在阅读源码的过程中,经常会看到这些符号<< ,>>,>>>,这些符号在Java中叫移位运算符,在写代码的过程中,虽然我们基本上不会去写这些符号,但需要明白这些 ...
- 位运算——左移右移运算详解
代码#include "stdio.h"char leftshift(char i, int n) {if(n < 0)return -1;return i<<n ...
- 【C语言】操作符详解(超详细)
hello~~,我是~小鹿,超级详细的操作符讲解来康康吧 可以收藏随时找到这里哦~ [C语言]操作符详解(超详细) 1.算数操作符:+,-,*,/,% 2.位移操作符:<< , >& ...
- C语言学习笔记—P13(操作符详解<1>+图解+题例)
目录 前言:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教! --By 作者:新晓·故知 操作符详解<1>: 题例: 1. 操作符分类: 算术操作符 移位操作 ...
最新文章
- pku 3422 Kaka's Matrix Travels 最大费用最大流
- 项目CPU异常高分析
- 错误请联系管理员文件 index.php,ThinkPHP5框架在写项目过程中遇到的相关问题,以及前端问题-Go语言中文社区...
- Chrome浏览器不支持字体小于12px的解决办法
- Sword STL之map效率问题
- C++中如何去掉std::string对象的首尾空格
- java printwriter 文件_java – 如何使用printwriter创建和写入文件
- Win11控制面板里面怎么找到系统安全?
- 【2017年第3期】开放政府环境下医药公司与医生之间的价值转移
- java ntpudpclient_使用NTP获取网络时间-----java
- Spark之StructuredStreaming
- android tools add native support,使用NDK进行开发android
- 【Tensor】(张量)的基本概念和操作
- steam安裝位置linux,steam盒子
- linux内核手写板驱动,【Linux系统编程应用】 Linux Input子系统(一)
- thinkphp 模板写php,thinkphp 模版继承的使用
- 腾讯、阿里、京东…互联网大厂2022新年礼盒长啥样?我酸了
- 2018优秀讲师排行榜出炉,将受邀出席开发者大会!
- html设置右键失灵,鼠标右键失灵是怎么回事
- 2023年天津医科大学药学考研考情与难度、参考书及上岸前辈经验