我是靠谱客的博主 精明棒棒糖,最近开发中收集的这篇文章主要介绍day25.1-汇编和C的移位指令,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、为什么要位运算

  • 位运算的效率很高
  • 因为计算机处理的都是一些二进制数,计算机不懂我们所说的加减乘除,这些所有的运算,计算机最后都会使用位运算得到结果
  • 位运算还可以用来加密

二、汇编中的移位指令

1.算数移位指令

  • SAL(Shift Arithmetic Left):算术左移(和SHL效果一样)

  • SAR(Shift Arithmetic Right):算术右移

  • 格式:SAL/SAR Reg/Mem, CL/Imm

    即算数移位指令后面的第一个操作数是寄存器或者内存;第二个操作数是寄存器或者立即数

    SAL eax,2
    SAL ax,1
    SAL al,3
    
  • 怎么实现:

    • 如果SAL eax,1,表示将eax中的数(4字节)左移1位,最高位的数移入到CF进位标志位中,最低位补0

    • 如果SAR ax,1,表示将ax中的数(2字节)右移1位,最高位的补原来的ax中的符号位(原来的最高位),最低位移入到CF进位标志位中

      举例:
      SAR al,1
      //al:10000001右移一位最高位补原来符号位,最低位移入CF,即11000000 / CF:1
      SAL al,2
      //al:10000001左移两位最高位移入CF,最低位补0,即00000100
      /
      CF:0
      
    • 如果是移动位数大于1,就一个一个依次按照移动1位这样做

  • 特殊:

    SAL al,8
    //表示将al寄存器中8位全部变成0
    SAR ax,0x10
    //表示将ax寄存器中16位全部原来最高位的符号位
    

    为什么sar/sal eax,0x20有点问题

2.逻辑移位指令

  • SHL(Shift Left):逻辑左移

  • SHR(Shift Right):逻辑右移

  • 格式:SHL/SHR Reg/Mem, CL/Imm

    SHL eax,2
    SHR word ptr es:[ebp],1
    SHL al,1
    
  • 怎么实现:

    • 如果SHL eax,1,表示将eax中的数(4字节)左移1位,最高位的数移入到CF进位标志位中,最低位补0

    • 如果SHR al,1,表示将al中的数(1字节)右移1位,最高位补0,最低位移入到CF进位标志位中

      举例:
      SHR al,1
      //al:10000001右移一位最高位补0,最低位移入CF,即01000000
      /
      CF:1
      SHL al,1
      //al:01000001左移一位最高位移入CF,最低位补0,即10000010
      /
      CF:0
      

3.循环移位指令

  • ROL(Rotate Left):循环左移

  • ROR(Rotate Right):循环右移

  • 格式:ROL/ROR r/m, i8/CL

    ROL eax,3
    ROL cx,1
    ROR cl,2
    
  • 怎么实现:

    • 如果ROL eax,1,表示将eax中的数循环左移1位,最高位的数补到最低位,并且最高位的数移入CF标志位

    • 如果ROR al,1,表示将al中的数循环右移1位,最低位的数补到最高位,并且最低位的数移入CF标志位

      举例
      ROL al,1
      //al:10000001循环左移一位最高位补到最低位,最高位移入CF,即00000011
      /
      CF:1
      ROR al,1
      //al:10000001循环右移一位最低位补到最高位,最低位移入CF,即11000000
      /
      CF:1
      

4.带进位的循环移位指令

  • RCL(Rotate through Carry Left):带进位循环左移

  • RCR(Rotate through Carry Right):带进位循环右移

  • 格式:RCL/RCR r/m, i8/CL

    RCL eax,1
    RCR cx,2
    RCR al,1
    
  • 怎么实现:

    • 如果RCL al,1,表示将al中的数循环左移一位,最高位移入CF标志位,并且CF原来的数补到最低位

    • 如果RCR al,1,表示将al中的数循环右移一位,最低位移入CF标志位,并且CF原来的数补到最高位

      举例:
      RCL al,1
      //al:10000001,CF:0循环左移一位最高位移入CF,CF原来的数补到最低位,即al:00000010 / CF:1
      RCR al,1
      //al:10000001,CF:0循环右移一位最低位移入CF,CF原来的数补到最高位,即al:01000000 / CF:1
      

三、C语言中的移位运算

  • 与运算 &

    printf("%d",2&3);
    //2(写成二进制,按位做即可)
    
  • 或运算 |

    printf("%d",2|3);
    //3
    
  • 非运算 ~

    printf("%d",~2); //-3,因为%d打印的是有符号的整数
    
  • 异或运算 ^

    printf("%d",2^3);
    //1
    
  • 移位运算 << >>

    • 左移运算,有符号和无符号是无区别的

      int a = 8;
      printf("%d",a<<1);
      //16
      unsigned int b = 8;
      printf("%d",b<<1);
      //16
      

      查看反汇编:生成的汇编指令都是shl,逻辑左移

      屏幕截图 2021-12-18 105543
    • 右移运算,有符号对应SAR即算数右移,无符号对应SHR即逻辑右移

      int a = 0xF0000000;
      printf("%d",a>>1);
      //-134217728
      unsigned int b = 0xF0000000;
      printf("%d",b>>1);
      //2013265920
      

      查看反汇编:有符号右移生成的指令为SAR,无符号右移生成的指令为SHR

      屏幕截图 2021-12-18 110345

四、作业

  • 定义一个unsiged char 类型,通过程序为第3、5、7位赋值,赋值时不能影响到其它位原来的值(使用位操作指令)

    #include "stdafx.h"
    #include "stdlib.h"
    void Func(unsigned char a){//假设第3,5,7位要赋的值1,0,1
    a = a | 0x44;
    //0100 0100
    a = a & 0xef;
    //1110 1111
    printf("%x",a); //0110 0100
    }
    int main(int argc,char* argv){
    unsigned char a = 0x34;
    //0011 0000
    Func(a);
    system("pause");
    return 0;
    }
    
  • 判断某个位的值是否为1

    #include "stdafx.h"
    #include "stdlib.h"
    void Func(unsigned char a){//假设要判断第三位的值是否是1
    if((a & 0x04) == 0){
    //0000 0100
    这里一定要大括号,因为位运算优先级很低
    printf("不是1");
    }else{
    printf("是1");
    }
    }
    int main(int argc,char* argv){
    unsigned char a = 0x34;
    //0011 0100
    Func(a);
    system("pause");
    return 0;
    }
    
  • 读取第7、6、5位的值,以十进制显示(unsigned)

    #include "stdafx.h"
    #include "stdlib.h"
    void Func(unsigned char a){
    a = a & 0x70;
    //0111 0000
    a = a >> 4;
    printf("%d",a);
    }
    int main(int argc,char* argv){
    unsigned char a = 0x54;
    //0101 0100
    Func(a);
    system("pause");
    return 0;
    }
    
  • 用十六进制文本编辑器分别打开一个.exe、.dll、.sys、.txt、.doc、.jpg、.pdf等将前两个字节写在下面

    • .exe:内存中显式为4D 5A,我们读作0x5A4D
    • .dll:同样是4D 5A
    • .sys:4D 5A开头,但也有25 75
    • .txt:0A 66,读作0x660A
    • .doc:D0 CF,读作0xCFD0
    • .jpg:FF D8
    • .pdf:25 50,读作0x5025
  • 将一个在十六进制编辑器中打开的.exe文件,拖拽到最后,观察文件中的大小和硬盘上的大小

    屏幕截图 2021-12-18 130127

    可以发现用十六进制编辑器打开一个.exe文件,它的最大地址0x0829CDFF,换算成10进制等于136957439字节,我们发现该文件是从地址0x00000000开始算的,所以算大小还要加1字节,即136957439+1=136957440字节

    小提示:winhexoffset栏单击一下,可以在十进制和十六进制之间转换显示

最后

以上就是精明棒棒糖为你收集整理的day25.1-汇编和C的移位指令的全部内容,希望文章能够帮你解决day25.1-汇编和C的移位指令所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部