IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C/C++中的移位运算你真的搞懂了吗?一文看懂移位运算 -> 正文阅读

[C++知识库]C/C++中的移位运算你真的搞懂了吗?一文看懂移位运算

移位运算,很多人都是知道,但是又没有完全懂。这是因为移位运算的规则还是稍微有点复杂。因为移位运算分有左移、右移,同时还得区分逻辑移位和算术移位,并且还需要考虑移位超出数据长度的情况。

1 概念区分

首先,左移、右移和算术移位、逻辑移位是交叉的关系,并不是四个并列关系。可以这么讲,左移和右移都可以分为算术移位、逻辑移位,也可以反过来将,算术移位、逻辑移位里面都可以分为左移、右移。所以这几个概念没有办法分开讲。
左移与右移:就是将数据整体左移,然后最左边的位(最低位)被丢弃,最右边的位(最高位)空出来,称为缺位。右移恰好相反。如下图所示(为了方便,以4bit数据为例):
在这里插入图片描述
左移(无论是算术左移还是逻辑左移),缺位一律填充为0。因此,对左移运算来讲,算术移位和逻辑移位的结果是一样的,不需要区分

算术移位与逻辑移位:这个两个的本质区别在于移位(右移)之后如何填充缺位

  • 对于逻辑移位,缺位一律填充0。
  • 对于算术移位,缺位填充符号位,即非负数填0,负数填1

对于非负数来讲,符号位为0,因此算术右移之后,缺位填充0,与逻辑右移一样,因此,非负数逻辑右移与算术右移结果一样

通过以上的分析,可以得出如下结论:

  • 左移 ,算术左移和逻辑左移结果一样,不用区分。
  • 右移,如果是非负数,算术右移和逻辑右移结果一样,不用区分。
  • 右移,如果是负数,算术右移和逻辑右移结果不一样。

2 编译器如何选择是逻辑移位还是算术移位

我们在编码的时候,可以用<< 以及 >> 分别表示左移和右移,但是编译器是如何区分这是算术移位还是逻辑移位呢?

  • 如果是左移,不用区分逻辑移位还是算术移位,因为结果一样。
  • 如果是右移,编译器需要根据数据的类型选择,如果是unsigned 类型(无符号),选择逻辑右移,如果是signed类型,选择算术右移。

因此,如果是signed类型数据,想要进行逻辑移位,可以强转为unsigned和类型后进行移位。unsigned类型要想进行算术移位,可以强转为signed类型后进行移位。

3 移位位数超过数据长度了编译器如何处理?

首先,我们编码时,无论是移位运算还是其它计算,都需要尽可能避免数据溢出,或者需要注意这点。一般,当移位的长度大于等于数据的长度时,编译器一般都会产生告警提示。如果真的移位长度m超过了数据长度len,编译器是怎么处理的呢?

  • 如果是左移,常量和变量处理不同:
    常量,移位长度超过数据长度,直接变为0
    变量,实际移位长度为m %len,以32为int数据为例,如果左移40位,实际上移位 40 % 32 = 8位
  • 右移的话,按照规则补位即可。

一个例子

下面通过一个例子,直观感受不同情况下移位的结果:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    /* 左移:
        1.不区分逻辑移位和算术移位,一律低位补0,高位丢弃
        2.当移位长度大于数据类型长度时,如果是常量,结果为0,若是变量,移位长度对数据长度取余
    */
    int a = 1;
    cout << "const 1 <<  2: " << (1 << 2) << endl;
    cout << "var a 1 <<  2: " << (a << 2) << endl;
    cout << "const 1 << 34: " << (1 << 34) << endl; // 常量移位长度超过数据长度,结果为0
    cout << "var a 1 << 34: " << (a << 34) << endl; // 变量移位长度超过数据长度,34 % 32 = 2,左移2位
    // 由于左移丢弃最高位,对于signed类型数,最高位为符号位,因此符号位变化,可能正数变负数,负数变正数
    int b = 0x80000001;  // 最高位bit为1000,符号为1,负数
    int c = 0x40000001;  // 最高位bit为0111,符号为0,正数
    cout <<"b: " << b << "  c: " << c << endl;
    cout << "b << 1: " << (b << 1) << endl; // b最高位1被移除,最高位变为0,负数变正数
    cout << "c << 1: " << (c << 1) << endl; // c最高位0被移除,最高位变为1,正数变负数
    cout << endl;
    /* 右移:
    有符号数 编译器采取算术右移,最高位补符号位,即非负数补0,负数补1
    无符号数 编译器采取逻辑右移,最高位补0
    所以,非负数 和 无符号数 不断右移的最终结果为0, 负数 不断右移的结果为 -1
    另外,从结果看,右移从结果都是变为原来数的1/2(奇数要取整),但是-1除外,
    因为-1右移结果还是-1 !,这是因为-1的二进制补码已经全是1了,即:111...111,共32个1
    右移之后,右边丢弃一个1,左边最高位在补充一个1,结果一样嘛,这也是为上面所有的负数一直右移
    最终结果都是-1
    */
   int d = -2;
   unsigned int e = 2;
   int f = -1;
   cout << d << " " << (d >> 1) << endl;
   cout << e << " " << (e >> 1) << endl;
   cout << f << " " << (f >> 1) << endl;
   cout << d << " " << (d >> 33) << endl;
    return 0;
}

运行结果如下:
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:13:43  更:2022-10-17 12:14:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 11:11:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码