当前位置 : 主页 > 编程语言 > c++ >

技巧“c”

来源:互联网 收集:自由互联 发布时间:2021-06-23
一、逻辑运算符 1、或运算(c语言中的 || ) 条件真和假 : 非零为真,零为假 ++为+(假假为假) 截断原理 if(a || b) 判断前面是否为真,把认为可能行大的放在最前面 c = i || j; if (c) {

一、逻辑运算符

  1、或运算(c语言中的  ||  ) 

    条件真和假 : 

       非零为真,零为假

    ++为+(假假为假)

    截断原理  if(a || b) 判断前面是否为真,把认为可能行大的放在最前面

    c = i || j;

    if (c) {}

    以汇编指令去看

    /*

009E1014 |. C745 FC 330>mov [local.1],0x33
009E101B |. C745 F4 660>mov [local.3],0x66
009E1022 |. 837D FC 00 cmp [local.1],0x0
009E1026 |. 75 0F jnz short 汇编.009E1037    // jnz 不为0 跳转  因 local-1  与  0 比较 不为0 跳转 ,所以导致第二个参数不用判断,效率快

009E1028 |. 837D F4 00 cmp [local.3],0x0       // 如果为0不跳转, 则继续与第二个参数比较  (假假为假)

009E102C |. 75 09 jnz short 汇编.009E1037
009E102E |. C745 F0 000>mov [local.4],0x0
009E1035 |. EB 07 jmp short 汇编.009E103E
009E1037 |> C745 F0 010>mov [local.4],0x1
009E103E |> 8B45 F0 mov eax,[local.4] ; 汇编.envpcurity_cookie_complement
009E1041 |. 8945 F8 mov [local.2],eax
009E1044 |. 8BC0 mov eax,eax

     */

  

  2、按位或(c语言中的 |)  

      0x33 ==>>   00 11 00 11

    | 0x66         + 01 10 01 10

       =  0x77 ==>  = 01  11 01 11   (假假为假) 

    /*

009E1046 |. 8B4D FC mov ecx,[local.1] ; msvcr100.72AD266D
009E1049 |. 0B4D F4 or ecx,[local.3]
009E104C |. 894D F8 mov [local.2],ecx ; msvcr100.__initenv

    */

    汇编是使用 or 指令 

   3、与运算

    ==>>逻辑与(c语言中的 && )

        真真为真

      c = a && b    //  自己的代码  a 认为 是假 放在前面   。判断前面是否为假,把认为可能行大的放在最前面

      if ( c ){}

      截断原理

    ==>>按位与 (c语言中的 &)

      0x33 ==>>    00 11 00 11

    & 0x66         + 01 10 01 10

       =  0x22 ==>   =  00 10 0010  (真真为真) 

    /*

  4、非运算

    (1)逻辑取反(c语言中的 ! )

       假变真, 真变假

      sete(setz)       取ZF标志位的值保存

      setne(setnz)   将ZF标志位的值取反保存

      (2)  按位取反(c语言中的 ~ )

        

    c语言代码中的汇编指令

      #include <cstdio>
      int main(){
      printf("fsadfasd");
      int i, j;
      i = 0x7787;
      j =  !i ; // 0

      /*

      

      */

      __asm mov eax, eax
      j = ~i;

          

 

 

 


      return 0;

      }

       NOT 指令

 

   5、异或运算

     (1)按位异或(c语言中的^)

      1^1 = 0 , 0^0 = 0  ,相同为0

      0^1 = 1 , 1^0 = 1  ,   不同为1

      eg :   1101

          ^ 0110

         = 1011  

      

 

 

 

      经典练习题:

        (1)不借助第三个变量,将两个数交换(数值大的数会有问题,溢出)

            int a = 5, b = 7;

            a = a+b;   // a = 12

            b = a - b;  // b = 12 - 7 = 5

            a = a - b;  // a = 12 - 5 = 7

        (2)用异或计算高效

          

 

    逻辑运算指令总结:

       (1) or :  按位或运算,假假为假(有1为1,全0为0)

          如:101100

           |   110101

           =  111101

       (2)  and : 按位与运算,真真为真(有0为0,全1为1)

          如: 101100

           &   110101

           =   100100

       (3) Not: 取反运算

          如:not  1011

              =   0100

        (4)  xor : 异或运算(相同为0,不同为1)

          如 :   101100

            ^  110101

            =  011001

                  

二、字符操作相关指令

  1、字符串的比较函数 strcmp 反汇编分析:

  2、REPNE和SCASB指令

    (1)SCASB指令:

      SCASB编译后:

        SCASB  BTYP PTR ES:[EDI]  char   s1[0]   byte 1  

        //// SCASW WORD PTR [EDI]      short  s1[0]  word  2

        //// SCASD  DWORD PTR [EDI]   int      s1[0]   dword 4

      相当于

        cmp byte prt [edi], al

       对标志位的影响相当于SUB指令,同时还会修改寄存器EDI的值

        如果标志位DF为0, 则  inc  EDI

        否则,dec EDI

      

    (2)REPNE指令(连续执行)

        repnz scasb 编译后 :repne scas bype ptr es:[edi]

        当ecx != 0 并且 ZF = 0 时,重复执行后边的指令 scas bype ptr es:[edi]

        每执行一  次EDI的值加1,ECX的值减1

        

         //   此汇编代码 是 获取字符的长度  (主要是实现逻辑思想)

        repne 和 repnz 是同一条指令的不同助记符

  3、REPE/REPZ和CMPSB, CMPSW, CMPSD指令

    (1)CMPS

        cmps byte ptr [edi] , byte ptr [esi]

        cmps word ptr [edi] , byte ptr [esi]

        cmps dword ptr [edi] , byte ptr [esi]

        对标志位的影响相当于sub指令, 同时还会修改寄存器EDI和ESI的值

          如果标志DF为0, 则EDI, ESI按相对于大小(byte, word, dword) 递增

          如果标志DF为1, 则EDI, ESI按相对于大小(byte word dword) 递减

    (2)REPE/REPZ

        repe/repz cmpsb 当ecx!=0并且zf = 1时, 重复执行后面的指令

        每执行一次ecx的值减1

    (3)实例运用

        比较串是否相等

        

      (4)汇编编写字符串比较函数

         (1)asm_strcmp 函数

            _declspec(naked)  告诉编译器用纯汇编方式编译函数, 不自动添加

                      寄存器保护和堆栈平衡代码

         (2)STD/CLD指令(DF方向标志位相关)

            std   df = 1

            cld   df =  0

 三、串存储和串的加载指令

    (1)串存储指令STOSB、STOSW、STOSD

        STOSB  STOS BYTE PTR [EDI]

        STOSW  STOS WORD PTR [EDI]

        STOSD  STOS  DWORD PTR [EDI]

        相当于:

          mov byte    ptr [edi], al

          mov word   ptr [edi], ax

          mov dword ptr [edi], eax

          rep stosb    rep stos byte ptr [edi]

          用al 的值 填充byte ptr [edi],每次ecx值减1,edi加1

     定位main()函数位置的步骤:

      第一步:打开程序, 程序启动后停在这里,直接jmp跳转

      第二步:jmp跳转跟随之后, 找到call  dword ptr [<xxxxx.exit>]退出的代码的位置

      第三步:call dword ptr [<xxxxx.exit >] 前一个call就是main函数。

    (2) 串载入指令LODSB, LODSW,LODSD

      lodsb lods byte ptr [esi]

      lodsw lods woedptr [esi]

      lodsd lods dword ptr [esi]

      

     rep lodsb ==>> rep lods byte ptr [esi]

     用byte ptr [esi]  的值, 填充al, 每次ecx值减1 , esi的值加1

上一篇:C++问题
下一篇:关于C++的智能指针
网友评论