zoukankan      html  css  js  c++  java
  • 汇编语言的分支程序设计与循环程序设计

    汇编语言的分支程序设计:

    例题1:比较三个无符号数的大小,按照从大到小的顺序排列

    关键的语句是:无符号数,因此所用语句是JAE实现跳转:

    此外比较两个操作数所用的是CMP,交换两个操作数的是XCHG

    书上的代码:

    代码1:这样写法比较占用寄存器,但是寄存器之间交换数值比较快

    ;程序名称:实现三个无符号数的由小到大的排序
    DATAS  SEGMENT
    BUFFER   DB   87,234,123
    DATAS  ENDS
    
    CODES   SEGMENT
                        ASSUME  CS:CODES,DS:DATAS
    START:    MOV   AX,DATAS
                        MOV    DS,AX
                        
                        MOV    SI,OFFSET  BUFFER;把buffer的 偏移量交给变址寄存器SI
                        MOV    AL,[SI]
                        MOV    BL,[SI+1]
                        MOV    CL,[SI+2]
                        CMP        AL,BL  ;比较AL,和BL的大小
                        JAE            NEXT1  ;如果AL>BL转移到next1
                        XCHG   AL,BL;交换AL,和BL
    NEXT1:   CMP     AL,CL  ;比较AL和CL的大小
                        JAE            NEXT2
                        XCHG    AL,CL
    NEXT2:   CMP     BL,CL
                        JAE       NEXT3
                        XCHG    BL,CL
    NEXT3:   MOV      [SI],AL    
                        MOV      [SI+1],BL
                        MOV      [SI+2],CL
                        MOV           AH,4CH
                        INT                21H
    CODES    ENDS
                        END    START
    View Code

     代码2:这样的写法只用了AL,但是寄存器与存储器操作数指教的操作比较慢

     1 ;程序功能,实现三个数的大小排序
     2 DATAS     SEGMENT
     3 BUFFER   DB    87,234,123
     4 DATAS     ENDS
     5 
     6 
     7 CODES      SEGMENT
     8 ASSUME  CS:CODES,DS:DATAS
     9 START:    MOV   AX,DATAS
    10                     MOV   DS,AX
    11                     
    12                     MOV     SI,OFFSET  BUFFER
    13                     MOV     AL,[SI]
    14                     CMP     AL,[SI+1]
    15                     JAE       NEXT1
    16                     XCHG   AL,[SI+1]
    17                     MOV     [SI],AL
    18 NEXT1:   CMP      AL,[SI+2]
    19                     JAE        NEXT2
    20                     XCHG    AL,[SI+2]
    21                     MOV      [SI+1],AL
    22 NEXT2:   MOV       AL,[SI+1]
    23                CMP      AL,[SI+2]
    24                JAE        NEXT3
    25                XCHG     AL,[SI+2]
    26                MOV       [SI+1],AL
    27 NEXT3:   MOV        AH,4CH
    28                     INT         21H
    29 CODES    ENDS
    30                    END        START
    View Code

    例题2:写一个实现一位十六进制的数转换为对应的ASCII码的程序 

    ;程序功能,实现16进制数值转换成对应的ASCII码
    ;原理:但十六进制数值为0到9的时候,对应的ASCII=x+30H
    ; 当十六进制为10到15的时候,对应的ASCII = x+37H

    这里关键的语句是 JA,大于9的话,转移

    之后便是程序跳转指令:JMP,但标号很多的时候,可以用LAB1,LAB2,LAB3这种类型的标号

     1 ;程序功能,实现16进制数值转换成对应的ASCII码
     2 ;原理:但十六进制数值为0到9的时候,对应的ASCII=x+30H
     3 ;            当十六进制为10到15的时候,对应的ASCII = x+37H
     4 DATAS            SEGMENT
     5 XX         DB      4
     6 ASCII     DB      ?
     7 DATAS   ENDS
     8 ;
     9 
    10 CODE     SEGMENT 
    11 ASSUME       CS:CODE,DS:DATAS
    12                      MOV   AX,DATAS
    13                      MOV   DS,AX
    14                      
    15 START:         MOV   AL,XX
    16                           AND    AL,0FH
    17                     CMP   AL,9
    18                     JA     LAB1
    19                     ADD    AL,30H
    20                     JMP    LAB2
    21 LAB1:          ADD     AL,37H
    22 LAB2:          MOV    ASCII,AL
    23                           MOV    AH,4CH
    24                           INT      21H
    25 CODE           ENDS
    26                     END     START
    View Code

     例题3:写一个程序实现ASCII转换成对应的十六进制

     1 ;ASCII 转换为16进制数
     2 DATA     SEGMENT
     3 XX          DB       ?
     4 ASCII      DB      'a'
     5 DATA      ENDS
     6 ;
     7 
     8 CODE      SEGMENT
     9          ASSUME    CS:CODE,DS :DATA
    10 START:            MOV   AX,DATA
    11                         MOV   DS,AX
    12                          MOV    AL,ASCII
    13                          CMP   AL,0
    14 LAB:           JB      LAB5
    15                         MOV   AH,AL
    16                         SUB    AH,'0'
    17                         CMP   AL,'9'
    18                         JBE     LAB6
    19                         CMP   AL,'A'
    20                         JB       LAB5
    21                         MOV   AH,AL
    22                         SUB    AH,'A' -10
    23                         CMP    AL,'F'
    24                         JBE      LAB6
    25                         CMP     AL,'a'
    26                         JB        LAB5
    27                         MOV    AH,AL
    28                         SUB      AH,'a' -10
    29                         CMP      AL,'f'
    30                         JBE        LAB6
    31                         ;
    32 LAB5 :         MOV      AH,-1
    33 LAB6:                          MOV       XX,AH
    34                           MOV       AH,4CH
    35                           INT         21H
    36                           CODE      ENDS
    37                                          END         START
    View Code

    利用地址表实现多向分支

    当要根据某个变量的值,进行多种不同的处理时,就会产生了多向分支,多向分支在高级语言中常常用switch实现,在汇编语言中是使用地址表实现的

    DSEG    SEGMENT

    ……………………

    COMTAB  DW  COMA,COMB,COMC,COMD

                  DW  COME,COMF,COMG,COMH

    DSEG      ENDS

    ……………………

    计算如果地址表内的地址,之后调用路口地址表即可

    之后跳转指令用这个 JMP   COMTAB[BX]

    循环程序设计:

    例题1:用计数法控制循环

     1 ;程序功能,说明根据计数法控制循环体
     2 DSEG        SEGMENT
     3 SUM         DW            ?
     4 DSEG        ENDS
     5 
     6 CSEG            SEGMENT
     7 ASSUME         CS:CSEG
     8 
     9 START:     MOV    AX,40H
    10                     MOV DS,AX
    11                     MOV    SI,0
    12                     MOV CX,1024
    13                     XOR    AX,AX
    14 AGAIN:        ADD  AX,[SI]
    15                     INC        SI
    16                     INC     SI
    17                     LOOP        AGAIN
    18                     ;
    19                     ASSUME  DS:DSEG
    20                     MOV    BX,DSEG
    21                     MOV    DS,BX
    22                     MOV    SUM,AX
    23                     MOV    AH,4CH
    24                     INT       21H
    25                     CSEG    ENDS
    26                                     END    START
    View Code

    本例程中所用的关键指令为LOOP,LOOP指令使用的方法是在初始化CX的初值,每次执行一次LOOP,CX寄存器会减一

    此外,还用了SI这个源地址指针,因为定义的变量时字,所以SI在循环的时候,调用了两次INC,在得到校验和的时候,重新设置了

    数据段寄存器,以便于保存校验和

    例题2:不用乘法指令实行乘法运算

    假设乘法时234*125,不用乘法指令,可以有移位和累加两种方法

    方法一:累加,可以看成是125个234相加,因此循环的时候,循环次数是CX=125

     1 ;程序功能,说明根据计数法控制循环体
     2 DSEG        SEGMENT
     3 SUM         DW            ?
     4 DSEG        ENDS
     5 
     6 CSEG            SEGMENT
     7 ASSUME         CS:CSEG
     8 
     9 START:     MOV    AX,40H
    10                     MOV DS,AX
    11                     MOV    SI,0
    12                     MOV CX,1024
    13                     XOR    AX,AX
    14 AGAIN:        ADD  AX,[SI]
    15                     INC        SI
    16                     INC     SI
    17                     LOOP        AGAIN
    18                     ;
    19                     ASSUME  DS:DSEG
    20                     MOV    BX,DSEG
    21                     MOV    DS,BX
    22                     MOV    SUM,AX
    23                     MOV    AH,4CH
    24                     INT       21H
    25                     CSEG    ENDS
    26                                     END    START
    View Code

    这里用的指令时XOR,自己和自己异或等于0,还有JCXZ这条指令,JCXZ表示但cx寄存器为0的时候跳转

    例题3:把16位的二进制数转换为5位十进制数值,为了简单,设二进制数时无符号的,采用8421BCD码表示十进制数

     1 ;程序功能,实现十六位二进制数转换为十进制数
     2 DSEG        SEGMENT
     3 DATA         DW        23456
     4 BUFFER    DB         5    DUP(0)
     5 JM                DW        10000,1000,100,10,1
     6 DSEG        ENDS
     7 
     8 CSEG            SEGMENT
     9                     ASSUME    CS:CSEG,DS:DSEG
    10         START:MOV AX,SEG    DATA
    11                         MOV DS,AX
    12                         MOV DI,OFFSET  JM
    13                         MOV SI,OFFSET BUFFER
    14                         MOV CX,5
    15                         MOV AX,DATA
    16                         XOR DX,DX
    17         NEXT: MOV BX,[DI]
    18                      ADD DI,2
    19                      DIV BX
    20                      MOV [SI],AL
    21                      INC SI
    22                      MOV AX,DX
    23                      XOR DX,DX
    24                      LOOP NEXT
    25                      MOV AX,4C00H
    26                      INT 21H
    27                      CSEG ENDS
    28                                      END START
    View Code

    这里用了两个比较重要的概念,因为是16位的数值,因此必须明白,在进行16位的除法运算时,商保存在AX中,余数保存在DX中

    在进行8位的除法运算时,AL保存商,AH保存余数

    SEG可以返回变量所在的段值,OFFSET返回变量的偏移值,因此经常可以看到 MOV DI,OFFSET JM等等

    在进行除法运算时,DIV BX隐含的是AX/BX

    例题4

    把一个字符串中的大写字母改成小写字母的程序

     1 ;程序功能,把字符串中的大写字母改成小写字母
     2 DSEG        SEGMENT
     3 STRING   DB  'HOW  arR  YOu I',0
     4 DSEG          ENDS
     5 CSEG         SEGMENT
     6                 ASSUME  CS:CSEG,DS:DSEG
     7         START: MOV AX,DSEG
     8                         MOV DS,AX
     9                         MOV SI,OFFSET STRING
    10         AGAIN: MOV AL,[SI]
    11                         OR   AL,AL
    12                         JZ     OK
    13                         CMP AL,'A'
    14                         JB     NEXT
    15                         CMP AL,'Z'
    16                         JA        NEXT
    17                         OR    AL,20H
    18                         MOV [SI],AL
    19         NEXT:   INC   SI
    20                         JMP  AGAIN
    21             OK:   MOV AX,4C00H
    22                         INT   21H
    23            CSEG  ENDS
    24                            END   START
    View Code

    这里需要注意的是,在字符串后面添加了一个0,这里是用来判断字符串是否为结束完,用OR AL,AL来判断,因为自己和自己相或,得到的是本身,只有和0相或,才能得到0

    因此用JZ来转移到OK,

    此外

    比较CMP AL,'A',如果小的话用的是JB转移,

    判断CMP AL 'Z',如果大于的话JA转移,

     经过上面的判断可以得出AL中是大写字母,因此用OR AL,20H,把大写字母转换为小写字母

    如果上述条件不满足,则INC SI

    例题5

    ;写一个程序判定从地址0040:0000H开始的2048个内存字节党员中是否有字节A
    ;如果有字符A,则把第一个(按地址由小到大为序)含此指定字符的存储单元的地址偏移
    ;送到000:03FEH党员中,如果没有,则把特征值送到0FFFFH送到上述指定单元

     1 ;写一个程序判定从地址0040:0000H开始的2048个内存字节党员中是否有字节A
     2 ;如果有字符A,则把第一个(按地址由小到大为序)含此指定字符的存储单元的地址偏移
     3 ;送到000:03FEH党员中,如果没有,则把特征值送到0FFFFH送到上述指定单元
     4 ;
     5 SEGADDR  = 40H
     6 OFFADDR = 0
     7 COUNT = 2048
     8 KEYCHAR = 'A'
     9 SEGRESU = 0
    10 OFFRESU = 3FEH
    11 ;
    12 CSEG            SEGMENT
    13                     ASSUME  CS:CSEG
    14                     START:MOV AX,SEGADDR
    15                                   MOV DS,AX
    16                                   MOV SI,OFFADDR
    17                                   MOV CX,COUNT
    18                                   MOV AL,KEYCHAR
    19                     NEXT: CMP AL,[SI]
    20                                   JZ OK
    21                                   INC SI
    22                                   LOOP NEXT
    23                                   MOV SI,0FFFFH
    24                     OK:     MOV AX,SEGRESU
    25                                   MOV DS,AX
    26                                   MOV BX,OFFRESU
    27                                   MOV [BX],SI
    28                                   MOV AH,4CH
    29                                   INT 21H
    30                     CSEG   ENDS
    31                                     END  START
    View Code

    代码分析:首先是等号的运用  =  ,常量的定义,类似于define

    在查找的时候,调用CMP AL,[SI],这个查找到的话,调用JZ类似于若相等,则跳转

    例题6

    ;设缓冲区中有一组单字节有符号数,以0为结束标志,写一个程序实现如下功能
    ;把前面5个正数一次送到缓冲区PDATA中,把前面5个负数送到缓冲区MDATA中,
    ;如果正数或者负数不足,则用0补足

     1 ;设缓冲区中有一组单字节有符号数,以0为结束标志,写一个程序实现如下功能
     2 ;把前面5个正数一次送到缓冲区PDATA中,把前面5个负数送到缓冲区MDATA中,
     3 ;如果正数或者负数不足,则用0补足
     4 
     5 MAX_COUNT  = 5
     6 DSEG         SEGMENT
     7 DATA         DB  3,-4,5,6,-7,8,-9,-10,-1,-32,-132,27,58,44,-12,0
     8 PDATA         DB  MAX_COUNT DUP (?)
     9 MDATA    DB  MAX_COUNT DUP (?)
    10 DSEG   ENDS
    11 ;
    12 CSEG            SEGMENT
    13                     ASSUME CS:CSEG,DS:DSEG
    14             START: MOV AX,DSEG
    15                             MOV DS,AX
    16                             MOV CX,MAX_COUNT
    17                             MOV SI,OFFSET PDATA
    18                             MOV DI,OFFSET MDATA
    19                             MOV AL,0
    20             NEXT1: MOV [SI],AL
    21                             MOV [DI],AL
    22                             INC SI
    23                             INC DI
    24                             LOOP NEXT1
    25                             MOV BX,OFFSET DATA
    26                             XOR SI,SI
    27                             XOR DI,DI
    28             NEXT2: MOV AL,[BX]
    29                             INC BX
    30                             CMP AL,0
    31                             JZ OVER
    32                             JG PLUS
    33                             CMP DI,MAX_COUNT
    34                             JAE CONT
    35                             MOV MDATA[DI],AL
    36                             INC DI
    37                             JMP SHORT CONT
    38             PLUS:  CMP SI,MAX_COUNT 
    39                             JAE  CONT
    40                             MOV PDATA[SI],AL
    41                             INC SI
    42             CONT: MOV AX,SI
    43                           ADD AX,DI
    44                           CMP AX,MAX_COUNT +MAX_COUNT
    45                           JB NEXT2
    46             OVER:  MOV AH,4CH
    47                             INT 21H
    48                 CSEG ENDS
    49                             END START
    View Code

    这个题目考了很多地方,当程序需要三个指针的时候,这个时候BX,SI,DI都可以作为指针

    这个题目相当的给力,可以好好看看

    版权所有:转载注明链接地址:http://www.cnblogs.com/fengdashen/p/3704148.html

  • 相关阅读:
    poj 3321 Apple Tree
    hdu 1520 Anniversary party
    Light OJ 1089 Points in Segments (II)
    Timus 1018 Binary Apple Tree
    zoj 3299 Fall the Brick
    HFUT 1287 法默尔的农场
    Codeforces 159C String Manipulation 1.0
    GraphQL + React Apollo + React Hook 大型项目实战(32 个视频)
    使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
    GraphQL + React Apollo + React Hook + Express + Mongodb 大型前后端分离项目实战之后端(19 个视频)
  • 原文地址:https://www.cnblogs.com/fengdashen/p/3704148.html
Copyright © 2011-2022 走看看