看到过很多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语言左移右移操作符详解相关推荐

  1. c语言左移右移运算符详解

    对于负数的右移:因为负数在内存中是以补码形式存在的,所以首先根据负数的原码求出负数的补码(符号位不变,其余位按照原码取反加1),然后保证符号位不变,其余位向右移动到X位,在移动的过程中,高位补1.等移 ...

  2. C语言基础之操作符详解

    C语言基础之操作符详解 操作符的分类 算术操作符 移位操作符 位操作符 逻辑操作符 逗号表达式 表达式求值 隐式类型转换 算术转换 操作符的属性 xwg今天就带各位大佬来了解一波C语言的操作符. 操作 ...

  3. C语言最全操作符详解,一文精通所有操作符!

    文章目录 前言 一.除号"/" 二."%"除法取余数 三.左移操作符"<<"和右移操作符">>" ...

  4. C语言左移右移操作符

    目录 一.整数在内存中的存储方式 1.原码,补码,反码 2.注意事项 二.操作符 1.左移操作符 2.右移操作符 先介绍整数在内存中的存储方式 一.整数在内存中的存储方式 数子的表示方法主要有原码,补 ...

  5. c语言智力题 操作符详解例题 数据存储 指针初阶 水仙花数 杨辉三角 逆序字符串 喝汽水问题 打印图形 猜凶手 使用指针打印数组内容 调整奇数偶数顺序 运动员猜名次

    [题目名称] 下面代码的结果是:a #include <stdio.h> int i; int main() {i--; //sizeof'的返回值是无符号整型if (i > siz ...

  6. 【C语言】sizeof操作符详解

    sizeof概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符+.-等:它并不是函数. 作用: 用于计算类型或者变量所占空间的大小(以字节为单位) 那么字节又是什么? 字节(Byte ) ...

  7. java 左移 返回值_java左移右移运算符详解

    在阅读源码的过程中,经常会看到这些符号<< ,>>,>>>,这些符号在Java中叫移位运算符,在写代码的过程中,虽然我们基本上不会去写这些符号,但需要明白这些 ...

  8. 位运算——左移右移运算详解

    代码#include "stdio.h"char leftshift(char i, int n) {if(n < 0)return -1;return i<<n ...

  9. 【C语言】操作符详解(超详细)

    hello~~,我是~小鹿,超级详细的操作符讲解来康康吧 可以收藏随时找到这里哦~ [C语言]操作符详解(超详细) 1.算数操作符:+,-,*,/,% 2.位移操作符:<< , >& ...

  10. C语言学习笔记—P13(操作符详解<1>+图解+题例)

    目录 前言:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教! --By 作者:新晓·故知 操作符详解<1>:​ 题例: 1. 操作符分类: 算术操作符 移位操作 ...

最新文章

  1. pku 3422 Kaka's Matrix Travels 最大费用最大流
  2. 项目CPU异常高分析
  3. 错误请联系管理员文件 index.php,ThinkPHP5框架在写项目过程中遇到的相关问题,以及前端问题-Go语言中文社区...
  4. Chrome浏览器不支持字体小于12px的解决办法
  5. Sword STL之map效率问题
  6. C++中如何去掉std::string对象的首尾空格
  7. java printwriter 文件_java – 如何使用printwriter创建和写入文件
  8. Win11控制面板里面怎么找到系统安全?
  9. 【2017年第3期】开放政府环境下医药公司与医生之间的价值转移
  10. java ntpudpclient_使用NTP获取网络时间-----java
  11. Spark之StructuredStreaming
  12. android tools add native support,使用NDK进行开发android
  13. 【Tensor】(张量)的基本概念和操作
  14. steam安裝位置linux,steam盒子
  15. linux内核手写板驱动,【Linux系统编程应用】 Linux Input子系统(一)
  16. thinkphp 模板写php,thinkphp 模版继承的使用
  17. 腾讯、阿里、京东…互联网大厂2022新年礼盒长啥样?我酸了
  18. 2018优秀讲师排行榜出炉,将受邀出席开发者大会!
  19. html设置右键失灵,鼠标右键失灵是怎么回事
  20. 2023年天津医科大学药学考研考情与难度、参考书及上岸前辈经验

热门文章

  1. iOS 禁止横屏的解决方案
  2. 七、树莓派做Aria2下载机
  3. 击鼓传花c语言编程题,转身之间——此间的少年画蛇添足版
  4. 软考高级 真题 2017年上半年 信息系统项目管理师 案例分析
  5. 如何快速批量修改图片尺寸?
  6. win10计算机用户名修改密码,win10怎么修改administrator账户密码?
  7. DataStore的基础用法
  8. html match函数,match函数的使用方法 match函数怎么使用
  9. 公元纪年法(儒略历-格里高历)转儒略日
  10. 【办公】如何把选择题做成excel文档