1、第五章 循环与分支程序设计,5.1 循环程序设计5.2 分支程序设计5.3 如何在实模式下发挥80386及其后继机型的优势,1. 编写汇编语言程序步骤 l 分析实际问题,确定解决问题的算法 l 按算法画出程序流程图 l 按流程图编写程序 l上机调试, 运行程序,注:本教材所讨论的编程环境只限于 在DOS操作系统下的实模式,2. 判断程序质量的标准 程序的正确性 程序的可读性 程序的执行时间 程序所占内存大小,3几种程序结构 顺序结构 循环结构 分支结构子程序结构,顺序结构形式,循环结构形式,当型循环(当条件成立进入循环),直到型循环(直到条件成立退出循环),分支结构形式,Y,Y,N,N,分支结
2、构形式,1多处调用完成同一功能的子程:code SEGMENTstart: 、 CALL subp 、 CALL subp 、 CALL subp 、 MOV AH, 4CH INT 21Hsubp PROC 、 、 RETsubp ENDPcode ENDS END start,2模块化程序设计:code SEGMENTbegin: CALL sub1 CALL sub2 CALL sub3 MOV AH, 4CH INT 21Hsub1 PROC 、 RETsub1 ENDPsub2 PROC 、 RETsub2 ENDPsub3 PROC 、 RETsub3 ENDPcode ENDS
3、END begin,子程结构形式,注意返回DOS语句位置,5.1.1 循环程序的结构形式,5.1 循环程序设计,(1)DO-WHILE结构 (2)DO-UNTIL结构,有关字符、数码转换的处理 1. 计算机处理字符时,常用的字符编码是ASCII 码。2. 数字和字母的ASCII码是一个有序序列数字09 : 30H 39H大写字母AZ : 41H 5AH小写字母az : 61H 7AH,5.1.2 循环程序设计方法,例5.1 将寄存器BX中的内容以十六进制形式显示出来。,BX是一个16位寄存器二进制 1010 1001 0011 1110,用十六进显示时,每4位用一个字符显示,共4个其中: 00
4、00 0 30H , 1010 A 41H 0001 1 31H , 1011 B 42H 、 、 1001 9 39H , 1111 F 46H,十六进制 A 9 3 E,屏幕上的显示 A 9 3 E,对应的ASCII 41H 39H 33H 45H,算法:取出要显示的某4位,转换为对应的ASCII码,再调用DOS系统功能进行显示。,(1) 对于00001001(09), 先扩展成一个字节,高4位清0, 加上30H后, 即可得字符09对应的ASCII码。 0000 0001B + 30H= 31H 0000 1001B + 30H=39H 0001B 1 1001B 9,(2) 对于1010
5、1111(AF), 先扩展成一个字节,高4位清0, 加上30H后, 还要再加上07H,才能得到AF 对应的ASCII码 0000 1010B+30H+07H = 41H 0000 1111B+30H+07H =46H 1010B A 1111B F,code SEGMENT ASSUME CS:codestart: MOV CH, 4 ;字符个数rotate: MOV CL, 4 ;循环移位次数 ROL BX, CL ;取显示位的值 MOV AL, BL ;保存在AL中 AND AL, 0FH ;清除高4位 ADD AL, 30H ;转变为数字的ASCII CMP AL, 3aH ;大于3aH
6、, 则应转变 JL print ;为数字09的ASCII ADD AL, 07H ;为字母AF的ASCII print: MOV DL,AL ;送 ASCII字符到DL MOV AH, 2 ;显示DL中的字符 INT 21H DEC CH ;显示结束? JNZ next MOV AH, 4CH ;返回DOS INT 21Hcode ENDS END start,例5.2 在ADDR单元中存放着数,度编制一程序把中1的个数存入COUNT单元中。,datarea segmentaddre dw 1234hcount dw ?datarea ends,mov cx,0mov bx,addremov
7、ax,bxagain:test ax,0ffffhjz exitjns shiftinc cxshift:shl ax,1jmp againexit:mov count,cxret,例5.4 将正数n插入一个已整序的字数组的正确位置。 x dw ? array_head dw 3,5,15,23,37,49,52,65,78,99 array_end dw 105 n dw 32 mov ax, n mov array_head-2, 0ffffh mov si, 0compare: cmp array_endsi, ax jle insert mov bx, array_endsi mov
8、array_endsi+2, bx sub si, 2 jmp short compareinsert: mov array_endsi+2, ax,例 5.5 i=Xi+Yi,LOGIC_RULEDW00DCHMOVBX,0MOVCX,10MOVDX, LOGIC_RULENEXT:MOVAX, XBXSHRDX,1JCSUBTRACTADDAX,YBXJMPSHORT RESULTSUBTRACT:SUBAX,YBXRESULT:MOVZBX,AXADDBX,2LOOPNEXTRET,例5.6 键入一行以空格开头以空格结束的字符串,datarea segmentbufferdb 80 du
9、p(?)flagdb ?datarea ends,lea bx,buffermov flag,0next:mov ah,01 ;读键盘int 21h ;所读内容放入altest flag,01h ;flag=1?jnz follow ;flag=0,zf=1不转cmp al,20h ;al是空格?,jnz exit ;不是,zf=0退出mov flag,1 ;置标志flag=1jmp nextfollow:cmp al,20h ;al是空格?jz exit ;是,zf=1,退出mov bx,al ;不是,保存inc bx ;数组索引加1jmp nextexit:,20,a,b,c,d,e,f,
10、20,flag= 0 1 jz exit成立,5.1.3 多重循环程序设计,基本方法与单重循环相同,但要注意:1、分别考虑各重循环的控制条件及其程序实现,相互之间不能混淆2、每次从外层循环再次进入内层循环时,初始条件要重新设置,例5.7 将首地址为a的字数组从大到小排序(气泡算法,多重循环) a dw 100,30,78,99,15,-1,66,54,189,256 mov cx, 10;待排序数的个数 dec cx;外循环的次数loop1: mov di, cx ;暂存外循环次数 mov bx, 0 ;数组下标loop2: mov ax, abx ;取第bx个数 cmp ax, abx+2
11、;与后一个数比较 jge continue ;bx=bx+2 xchg ax, abx+2 ;=,转移,不换xchg es:di+2,axmov es:di,axsub bx,bx ;排序标志cont:loop nextcmp bx,0 ;bx=1,已排好je initsorted:mov di,start_addr,练习5.11:从键盘输入一系列以$结束的字符串,统计数字字符的个数,data segmentcount dw 0buff db 50 dup(?)data endsprognam segmentmain proc farassume cs:prognamstart:push ds
12、sub ax,axpush axmov ax,datamov ds,axlea bx,buff ;取缓冲地址input:mov ah,01 ;从键盘读串int 21H ;存入al中mov bx,al ;保存字符,inc bx ;buff数组下标cmp al,$ ;是不是$jnz input ;是,结束读lea bx,buff ;取串地址mov ax,0next:mov cl,bx;取串中字符inc bx;指向下一字符cmp cl,$ ;是不是$jz disp ;是,zf=1,转移cmp cl,30h;与0比较jb cont ;9,不计数inc ax ;计数cont:jmp nextdisp:r
13、etmain endpprognam endsend start,练习5.11:测试一字符串是否存在数字,若存在,置CL第5位置1,否则置0,data segmentstring db abcqdefghijklmnopqrsdata endsprognamsegmentmain proc farassume cs:prognam,ds:data,es:datastart:push dssub ax,axpush axmov ax,datamov ds,axmov es,ax,begin:mov cx,20 ;字符个数mov si,0 ;数组下标again:mov al, stringsicm
14、p al,30h ;与0比较jb goon ;,转移or cl,20h ;有数字,置5位jmp exitgoon:inc si ;数组下标加1loop againand cl,0dfh ;无数字,清5位exit:retmain endpprognam endsend start,循环程序设计小结1、循环控制条件的选择:a. 循环次数已知,采用LOOPb. 循环次数已知,但有可能使用其他特征或条件结束循环, 可采用LOOPZ和LOOPNZc. 循环次数未知,具体问题具体分析2 、设立条件标志位的方法,5.2 分支程序设计,5. 2 .1分支程序的结构形式,双分支与多分支的共同特点:运行方向是向前
15、的在某一种特定条件下,只能执行其中的一个分支,5. 2 .1分支程序设计方法,1、使用CMP、TEST等运算型指令+条件转移指令2、使用逻辑尺的方法3、使用跳跃表法实现CASE结构,例5.9 折半查找:附加段有一个有序字数组,首字表示数组长度,AX是待查字,若找到CF=0,否则CF=1,dseg segmentlow_idxdw?high_idxdw?listdw12,11,22,33,44,55,66,77,88,99,111,222,333targetdw77dseg endscseg segmentmain proc farassume cs:cseg,ds:dseg,es:dsegst
16、art:push dssub ax,axpush axmov ax,dsegmov ds,axmov es,ax,例5.9 折半查找:附加段有一个有序字数组,首字表示数组长度,AX是待查字,若找到CF=0,否则CF=1,mov ax,target;lea di,list;取数组首地址cmp ax,es:di+2;取第1个数ja chk_last;第1个,检查最后1个lea si,es:di+2;=第1个je exit;,退出stc;CF=1,没找到jmp exitchk_last:mov si,es:di;下面三条使SI指向shl si,1;数组末元素add si,dicmp ax,es:si
17、;与末元素比较jb search;,头到末之后add cx,dx;以下三条计算shr cx,1;头与末的中点mov si,cxshl si,1;对准中间字,(1+5)/2=3 3*2=6 DI偏移6,即106,即第3字,compare:cmp ax,es:bx+si;比较,bx指向数组首元素je exit;,找到,退出ja highter;,调节搜索头dec cx;=mov high_idx,cx;调节搜索末jmp midhighter:inc cxmov low_idx,cx;调节搜索头jmp midno_match:stcexit:ret,例5.9 折半查找:附加段有一个有序字数组,首字表
18、示数组长度,AX是待查字,若找到CF=0,否则CF=1,例5.10 根据AL寄存器中哪一位为1(从低位到高位)把程序 转移到8个不同的程序分支去 。,branch_table dw routine1 dw routine2 dw routine3 dw routine4 dw routine5 dw routine6 dw routine7 dw routine8,注意:DW 标号的使用,寄存器间接寻址,cmp al, 0 je continue lea bx, branch_tableL : shr al, 1 ;逻辑右移,最低位进入CF位 jnb not_yet ;jnb=jnc,CF=0
19、,转移 jmp word ptr bx ;段内间接转移not_yet : add bx, type branch_table jmp Lcontinue: routine1: routine2: ,调试源程序,变址寻址方式实现,cmp al, 0 je continue mov si, 0 L : shr al, 1 ;逻辑右移,最低位进入CF位 jnb not_yet ; jnb=jnc,CF=0,转移 jmp branch_tablesi ;段内间接转移not_yet: add si, type branch_table jmp Lcontinue: routine1: routine2:
20、 ,调试源程序,基址变址寻址,cmp al, 0 je continue lea bx, branch_table mov si, 7* type branch_table mov cx, 8L : shl al, 1 ;逻辑左移,最高位进入CF位 jnb not_yet ;jnb=jnc,CF=0,转移 jmp word ptr bxsi;段内间接转移not_yet :sub si, type branch_table loop Lcontinue: routine1: routine2: ,调试源程序,习题5.21 试写一程序,要求比较数组ARRAY中的三个16位补码数,并根据比较结果在终
21、端上显示如下信息:(1)如果三个数都不相等,则显示0(2)如果有两个相等则显示1(3)如果都相等,则显示2,dseg segmentarray dw 3 dup(?)dseg endscseg segmentmov cx,3lea si,arraybegin:push cxmov cl,4mov di,4mov dl, mov ah,02int 21h,input:mov ah,01hint 21hand al,0fhshl dx,clor dl, aldec dijne inputmov si,dxadd si,2pop cxloop begin,compa:lea si, arraymov
22、 dx,0mov ax,simov bx,si+2cmp ax,bxjne next1inc dxnext1:cmp si+4,axjne next2inc dxnext2:cmp si+4,bxjne numinc dx,num:cmp dx, 3jl dispdec dxdisp:mov ah,2add dl,30hint 21hmain endpcseg endsend start,习题5.23 已定义整型变量、(1)若只有一个奇数,奇数存入,偶数存入(2)若两个奇数,A=A+1 B=B+1(3)若两个偶数,A、值不变,begin:mov ax,amov bx,bxor ax,bxtes
23、t ax, 1hjz class ;同奇同偶,转移text bx,1hjz exit,xchg bx,amov b,bxjmp exitclass:test bx,1hjz exit ;若同偶,退出inc b inc aexit:ret,5.3 如何在实模式下发挥80386及其后继机型的优势,80386及其后继机型不但兼容8086的程序,运行速度更快;而且还有其它的一些优势:,5.3.1 充分利用高档机的32位字长特征5.3.2 通用寄存器可作为指针寄存器5.3.3与比例因子有关的寻址方式,调试源程序例5.11,通用寄存器作指针寄存器8个32位通用寄存器都可以作为基址或变址寄存器使用,但注意它
24、们的高16位应为0。,32位字长特征计算机一次能够处理32位的数据,可以访问32位的8个通用寄存器,但EIP和EFLAGS在实模式下只有低16位可以使用。,比例因子方便了表格处理和多位数组处理,实模式段的大小限于64K,实模式下的程序是一种混合的16位和32位代码,纯16位模块(1) 所有段长都小于64KB;(2) 数据项主要是8位或16位的(3) 指向代码或数据的指针只 有16位偏移地址(4) 只有16位段之间传送控制,纯32模块(1) 段长可大于64KB(04GB);(2) 数据项主要是8位或32位的(3) 指向代码或数据的指针 有32位偏移地址(4) 只有32位段之间传送控制,8086/80286实模式,80386+保护模式,386+实模式下的程序在同一模块中,允许同时使用16位和32位的操作数和寻址方式段必须实16位的,但段中的指令可以是混合的16位和32位代码,奔腾4,第五章作业Page 1931955.10 5.21,