第 5章 基本结构程序设计第 5章 基本结构程序设计
5.1 程序设计的一般过程
5.2 顺序结构程序设计
5.3 分支程序设计
5.4 循环程序设计
5.5 字符处理第 5章 基本结构程序设计
5.1 程序设计的一般过程
5.1.1 程序与程序设计的概念要用计算机解决问题,必须事先对所要解决的问题拟定一个便于计算机工作的明确步骤,并且用计算机所能理解的“语言”
把它表示出来,输入计算机,经过调试正确,并最后运行取得结果后才算完成了任务,我们称这一过程为程序设计。把用计算机语言表示的问题求解的一系列明确步骤,称作解决该问题的程序,
而把完成这项任务的活动称为编码 (或称编制程序,简称编程 );
拟定一个便于计算机工作的明确步骤称为算法设计 (或称设计问题求解的方法 )。程序设计与编制程序是有区别的。程序设计除了包括编码外,还有其他过程,如算法设计,程序测试等。
第 5章 基本结构程序设计
5.1.2 算法与流程图
1.算法在编制程序之前,必须设计算法。算法是求解问题的方法和具体步骤,即把所要解决的问题表达为一系列计算机所能执行的基本操作。
例如:任意给定一个正整数 N,求出一切不超过 N的素数。
如果用筛选法来解决这一问题,则求解的步骤可概述如下:
第 5章 基本结构程序设计
(1) 将不超过 N的整数从小到大排成一串,即
1,2,3,4,…,N-1,N
(2) 划去数串最左边的数 1(可使用 *号标在该数的右上角 ),即
1*,2,3,4,…,N-1,N
此时数串留下的最左边的数为 2,而 2是一个素数,它是已识别的当前素数。
第 5章 基本结构程序设计
(3) 从当前素数 2起,划去数串右边所有 2的倍数的数 (2本身除外 ),即
1*,2,3,4*,5,6*,7,8*,9,10*,…
这样划去的都是合数,而右边剩下的就可能是素数。从 2起,
往数串右边看,首先遇到的是素数 3。
(4) 再从当前素数 3起,划去数串右边所有 3的倍数的数 (3本身除外 ),即
1*,2,3,4*,5,6*,7,8*,9*,10*,11,…
这样划去的都是合数。再从 3起往右边看,首先遇到的就是素数 5。
第 5章 基本结构程序设计如此继续下去,一直到找出的数 (此数不包括在所求素数中 )
刚好超过 N为止。这时,从该数起,数串左部中没有被划去的所有数就是所求的不超过 N的全部素数。
上述这样一个工作步骤,就是求出一切不超过 N的素数的
“算法”。
第 5章 基本结构程序设计
2.流程图在上述例题中,对于求解问题的算法描述用的是自然语言,
包括一些数学语言。但用这种方法来描述算法,对于求解问题的流程 (即逻辑结构 )还不是很直观,人们理解起来也比较慢。因此,人们往往利用具有几何图形直观性的流程图 (简称框图 )方法来描述算法,即给出问题求解步骤的图形表示,或是用某种类高级语言 (如类 PASCAL语言 )来描述算法,而流程图是描述算法最早使用的一种方法。
流程图是框和线 (或带箭头的线 )的集合体。框用以指示做什么事,线用以指示各框之间的关系 (包括顺序关系 )。框具有各种形状,表示各种不同的用途。国际标准化组织 ANSI/ISO对流程图使用的各种图形符号及其含义作了规定,本书不再讨论。
第 5章 基本结构程序设计
5.1.3 程序设计语言与编码用计算机来求解问题,还必须用计算机所能接受的语言将问题的算法表示出来,即编码或编程序。
编程序首先碰到的是使用何种语言的问题,这取决于两个因素,一是求解问题或任务的性质和要求,二是所用的计算机配置了什么语言。
第 5章 基本结构程序设计如前所述,在计算机系统的最内层是机器语言,它是裸机能直接理解的惟一语言。用机器语言编写程序虽可充分利用机器指令的灵活性,达到较高的效率,但这种程序是二进制代码形式,难读难写不便修改,现在已很少使用它,改用其外层的汇编语言来写“要求效率较高”的程序。汇编语言的主要思想是用符号表示机器指令,即用“记忆码”代替操作码,用“标识符”代替地址。与机器语言相比,它易读、易写,可以减轻人们的劳动。然而机器并不能直接理解汇编语言,因此必须要有一个翻译程序将汇编语言程序翻译成机器语言程序,这就是汇编程序。汇编语言是一种重要的程序设计语言。
第 5章 基本结构程序设计除了汇编语言,还有许多高级程序设计语言,如 PASCAL、
Visual C++等。使用这类高级语言编写的程序,同汇编语言程序一样,也必须经过相应语言的“编译程序”的翻译,使之成为机器语言程序,才能在机器上执行。
第 5章 基本结构程序设计
5.1.4 程序设计的一般过程程序设计包含了多方面的工作,尤其是解决大型复杂问题更是如此。程序设计一般要经历以下几个阶段。
1.定义问题这个阶段也称为要求定义分析,或称需求分析,即对要解决问题的意义和要求,了解明白准确。这包括制定一系列清晰而无二义性的规格说明。例如,问题要求什么样的精度,提供的输入是什么,以及期望的结果又是什么等等。这个阶段是十分重要的,对复杂问题更是这样。因为,需求分析产生的规格说明书是以后各阶段的依据,如果不把问题的含义弄明白、准确,
那将会导致整个设计的失败或返工。
第 5章 基本结构程序设计
2.构造解法概要这个阶段也称为功能设计,主要是制定整个解法的概要,
即总体设计。这包括将整个问题分解成若干任务或子任务 (可按功能划分任务 ),以及它们之间相互关系的描述。可采用功能模块分割法、逐步求精法等。
第 5章 基本结构程序设计
3.确定算法这个阶段也称为设计,主要是选择最优算法和数据结构以实现上述的每一个任务 (或子任务 ),即根据功能模块而选择最适当的方法和数据结构以实现之。这是程序设计的核心步骤,
也是比较困难的工作。
第 5章 基本结构程序设计
4.编码这个阶段也称为程序编制或编程,主要是选择一种程序设计语言,并用此语言具体地实现所设计的算法。
5.调试与排错通过调试来排除程序中的错误,保证程序的正确。一般要作静态检查和动态运行。静态检查包括人工检查和上机进行语法检查;动态运行就是根据程序在工作中所有可能的情况,例如,
输入各种不同的初始数据,检查程序执行是否正确。
第 5章 基本结构程序设计
6.整理文档程序设计的结果包括两大部分,一是程序,二是文档。这里讲的文档主要是包括各个设计阶段的规格说明书,以及用户使用手册等。这是用户使用、维护程序的依据。
7.软件测试测试是保证软件质量的重要手段,其主要方式是在设计测试用例的基础上检验软件的各个组成部分。首先是进行单元测试,查找各模块在功能和结构上存在的问题并加以纠正。其次是进行组装测试,将已测试过的模块按一定顺序组装起来。最后按规定的各项需求,逐项进行有效性测试,决定已开发的软件是否合格,能否交付用户使用。
第 5章 基本结构程序设计
8.运行 /维护已交付的软件投入正式使用,便进入运行阶段,这一阶段可能持续若干年甚至几十年。软件在运行中可能由于多方面的原因,需要对它进行修改。其原因可能有:运行中发现了软件中的错误需要修正;为了适应变化了的软件工作环境,需做适当变更;为了增强软件的功能需做变更等。
第 5章 基本结构程序设计
5.2 顺序结构程序设计例 5-1 若内存的数据段中,有缓冲区 BUFFER,存取数据的规则是先存储一个 16位带符号的被除数,再存储一个 16位带符号的除数,接着存储商,最后存储余数。
DATA SEGMENT
BUFFER DW 812DH ;被除数
DW 013CH ;除数
DW? ;存商
DW? ;存余数
DATA ENDS
第 5章 基本结构程序设计
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
第 5章 基本结构程序设计
LEA BX,BUFFER
MOV AX,[BX]
CWD ;扩展为 32位
IDIV 2[BX] ;带符号数除法
MOV 4[BX],AX ;存商
MOV 6[BX],DX ;存余数
RET
START ENDP
CODE ENDS
END START
第 5章 基本结构程序设计例 5-2 编制一个实现两个字 (16位 )相乘的程序。
MY_DATA SEGMENT
M1 DW 00FFH ;被乘数
M2 DW 00FFH ;乘数
P1 DW? ;存积
P2 DW?
MY_DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
第 5章 基本结构程序设计
ASSUME CS∶ COSEG,DS∶ MY_DATA,ES∶ MY_DATA
STR PROC FAR
MULT,PUSH DS
MOV AX,0
PUSH AX
MOV AX,MY_DATA
MOV DS,AX
MOV ES,AX
MOV AX,M1
第 5章 基本结构程序设计
MUL P2
MOV P1,AX ;存结果
MOV P2,DX
RET
STR ENDP
COSEG ENDS
END MULT
第 5章 基本结构程序设计
5.3 分支程序设计一般情况下,程序按顺序方式执行,有时也需要机器能根据不同情况,执行不同的程序或程序段,这就要求所编制的程序具有判断、选择的能力,即需要分支结构的程序。计算机的分析、
判断能力就是这样实现的。
分支结构的基本形式如图 5-1所示,当分支条件满足时执行程序段 1,不满足时执行程序段 2,当程序段 2为空时,分支结构为简单形式。
第 5章 基本结构程序设计图 5-1 分支结构示意图程序段 1 程序段 2
条件满足 不满足第 5章 基本结构程序设计
5.3.1 转移指令转移指令可以改变程序的执行顺序,它分为无条件转移指令和条件转移指令。
1.无条件转移指令格式,JMP OPRD
功能:无条件转移到 OPRD所指定的位置。
说明:根据目标地址 OPRD的位置,本指令还可继续划分为:
段内直接短转移、段内直接转移、段内间接转移、段间直接转移和段间间接转移五种具体的形式。
第 5章 基本结构程序设计
(1) 段内直接短转移。
格式,JMP SHORT LABEL
说明,LABEL为转移后目的地址的标号,转移后的地址标号必须在 -128~ +127之间。
(2) 段内直接转移。
格式,JMP NEAR LABEL
说明,LABEL为转移后目的地址的标号,转移后的地址标号必须在 -32 768 ~ +32 767之间。此外,一般将段内直接短转移和段内直接转移合并起来,写为 JMP LABEL的形式,具体属于哪种转移由 CPU在执行期间自动判断。
第 5章 基本结构程序设计
(3) 段内间接转移。
格式,JMP reg/mem
说明:转移的偏移量在寄存器 /存储器中。
(4) 段间直接转移。
格式,JMP FAR PTR LABEL
说明,LABEL为转移后目的地址的标号,转移后的地址与指令所在的地址不在同一个代码段中,因此 CS和 IP均需改变。
第 5章 基本结构程序设计
(5) 段间间接转移。
格式,JMP DWORD PTR mem
说明:转移后目的地址在存储器中,因为 CS和 IP均需改变,
所以需要 32位存储器操作数。
第 5章 基本结构程序设计例 5-3
JMP END ;转移到标号 END处,CS不变,IP改变
JMP FAR PTR NEXT ;转移到标号 NEXT处,CS改变,IP改变
JMP DWORD PTR [SI] ;将 DS∶ [SI]开始的 32位数据作为转移地址,; CS改变,IP改变第 5章 基本结构程序设计
2.条件转移指令
80x86的条件转移指令比较多,它以某些标志位的逻辑运算作为依据,若满足指令所规定的条件,则程序执行转移,否则顺序执行。在这类指令中,转向的目的地址必须在转移指令的 -
128列或 +127个字节之间,这些指令对标志位无影响,指令的助记符也不惟一。
格式,JCC LABEL
功能,如果满足判断条件 CC则转移到标号 LABEL处,否则继续执行下一条指令。
第 5章 基本结构程序设计说明:本指令还可继续划分成以下四种情况:
(1) 检测某一标志位的条件转移指令如表 5-1所示。
表 5-1 检测某一标志位的条件转移指令指令格式 转移条件 指令功能
JZ/JE LABEL ZF=1 为 0或相等时转移
JNZ/JNE LABEL ZF=0 不为 0或不相等时转移
JC LABEL CF=1 有进位或借位时转移
JNC LABEL CF=0 没有进位或借位时转移
JO LABEL OF=1 有溢出时转移
JNO LABEL OF=0 没有溢出时转移
JS LABEL SF=1 为负时转移
JNS LABEL SF=0 为正时转移
JP/JPE LABEL PF=1 结果为偶时转移
JNP/JPO LABEL PF=0 结果为奇时转移第 5章 基本结构程序设计
(2) 根据两个无符号数比较结果来决定转移的条件转移指令如表 5-2所示。
表 5-2 根据两个无符号数比较结果来决定转移的条件转移指令指令格式 转移条件 指令功能
JA/JNBE LABEL CF=0,ZF=0 大于时转移
JAE/JNB LABEL CF=0 大于等于时转移
JB/JNAE LABEL CF=1 小于时转移
JBE/JNA LABEL CF=1或 ZF=1 小于等于时转移第 5章 基本结构程序设计
(3) 根据两个带符号数比较结果来决定转移的条件转移指令如表 5-3所示。
表 5-3 根据两个带符号数比较结果来决定转移的条件转移指令指令格式 转移条件 指令功能
JG/JNLE LABEL SF=OF,ZF=0 大于时转移
JGE/JNL LABEL SF=OF 大于等于时转移
JL/JNGE LABEL SF≠OF 小于时转移
JLE/JNG LABEL SF≠OF或 ZF=1 小于等于时转移第 5章 基本结构程序设计
(4) CX/ECX为 0时转移的条件转移指令如表 5-4所示。
表 5-4 CX/ECX为 0时转移的条件转移指令指令格式 转移条件 指令功能
JCXZ LABEL CX=0 CX为 0时转移
JECXZ LABEL ECX=0 ECX为 0时转移第 5章 基本结构程序设计例 5-4 设( AL) =( DL),执行指令
CMP AL,DL
JZ NEXT
的结果是:指令 JZ NEXT执行完后将跳转到 NEXT标号处继续执行。
例 5-5 设 CL内容为一无符号数,执行指令
CMP CL,10
JB NEXT
的结果是:如果( CL) < 10,则跳转到 NEXT标号处继续执行;
如果 (CL)≥10,则继续执行下一条指令。
第 5章 基本结构程序设计例 5-6 设 CL内容为一带符号数,执行指令
CMP CL,0
JNG NEXT
的结果是:如果 CL为负数或 0,则跳转到 NEXT标号处继续执行;如果 CL为正数,则继续执行下一条指令。
第 5章 基本结构程序设计
5.3.2 分支程序设计在分支程序中,对条件的判断结果只有两种:“是”或者
“不是”。因此,分支程序一般有两种结构:不完全的双分支结构和完全的双分支结构,如图 5-2所示。图 5-2(a)是不完全的双分支结构,图 5-2(b)是完全的双分支结构。在不完全的双分支结构中,一个分支需要完成一定的任务,而另一个分支不需要完成任何任务;在完全的双分支结构中,两个分支都分别有各自的任务。
第 5章 基本结构程序设计图 5-2 分支程序的一般结构
(a) 不完全的双分支结构; (b) 完全的双分支结构开始分支程序条件结束
N
Y
( a )
开始条件分支程序段 1 分支程序段 2
结束
N Y
( b )
第 5章 基本结构程序设计例 5-7 给定两个数 X和 Y,分别在 X,Y是无符号数和带符号数的情况下比较 X,Y的大小。若 X大,则输出字母 X,若 Y大,
则输出字母 Y。
NAME EX_COMPARE_XY
STACK STACKSEG 500
MYDATA SEGMENT RW
X DW 0F040H ;指定 X,Y的值
Y DW 7321H
MYDATA ENDS
MYCODE SEGMENT ER
ASSUME DS∶ MYDATA,SS∶ STACK,CS∶ MYCODE
第 5章 基本结构程序设计
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,MYDATA
MOV DS,AX
MOV AX,X
CMP AX,Y ;无符号数情况下的比较
JA XN_BIG
MOV DL,'Y' ; Y大,输出 Y
MOV AH,02H
INT 21H
第 5章 基本结构程序设计
XN_BIG,MOV DL,'X' ; X大,输出 X
MOV AH,02H
INT 21H
MOV AX,X
CMP AX,Y ;带符号数情况下的比较
JG XS_BIG
MOV DL,'Y' ; Y大,输出 Y
MOV AH,02H
INT 21H
第 5章 基本结构程序设计
XS_BIG,MOV DL,'X' ; X大,输出 X
MOV AH,02H
INT 21H
MOV AH,4CH
INT 21H
MYCODE ENDS
END START
第 5章 基本结构程序设计
1.利用比较转移指令实现分支用于比较、判断的指令有:比较指令 CMP、串比较指令
CMPS、串搜索指令 SCAS。用于实现转移的指令有:无条件转移指令 JMP和各种类型的条件转移指令。它们都可以互相配合以实现不同情况的分支。对于多路分支的情况,可以采用多次判断转移的方法实现。每次判断转移形成两路分支,n次判断转移可以形成 n+1路分支。
第 5章 基本结构程序设计例 5-8 数据块的传送。
把内存中某一区域的源数据块传递到另一区域。若源数据块与目的数据块之间地址没有重叠,可直接用数据传送指令或串操作中的传送指令实现。若它们之间的地址重叠,如何实现数据块的传送呢?试编制一程序来解决这种情况的数据块传送问题。
问题分析:先判断源地址加数据块长度是否小于目的地址,
若小于,可按增量的方式传送;若不小于,则要把指针改为指向数据块的底部,然后采用减量方式传送。(这里假设从低地址区域向高地址区域传送。)程序描述如下:
第 5章 基本结构程序设计
DATA SEGMENT
STRG DB 1000 DUP(?)
STG1 EQU STRG+7
STG2 EQU STRG+25
STRSE EQU 50
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,
ES∶ DATA,SS∶ STACK
第 5章 基本结构程序设计
GOO PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV CX,STRSE ;计数器值送 CX
MOV SI,OFFSET STG1
MOV DI,OFFSET STG2
CLD ;增量方式( DF标志清零)
第 5章 基本结构程序设计
PUSH SI ;将偏移量 STG1入栈
ADD SI,STRSE-1 ;源地址加上块长
CMP SI,DI ;比较源串地址与目的串地址的大小
POP SI ;将偏移量 STG1出栈
JL OK ;若 [SI]<[DI]转移,表明无重叠区,按增量方式传送
STD ;减量方式传送,表明有重叠区
ADD SI,STRSE-1 ;指向数据块底部
ADD DI,STRSE-1
OK,REP MOVSB ;重复传送 50个数据
RET
GOO ENDP
COSEG ENDS
END GOO
第 5章 基本结构程序设计本程序设计时,考虑了两种情况:一是无重叠数据源,即源数据块长度小于目的地址,按增量方式传送;二是有重叠数据源,即源数据块长度大于目的地址,按减量方式传送。任何一个串操作指令,可在其前面加上一个重复操作前缀 REP,于是指令就重复执行直至在寄存器 CX中的操作次数满足要求为止。
重复操作是否完成的检测是在操作以前进行的:若初始化操作次数为 0,它不会引起重复操作;若基本操作是一个影响 ZF标志的操作,在重复操作前缀字节中也可以规定与标志 ZF相比较的值。在基本操作执行以后,ZF标志与指令的值不等,则重复终结。
第 5章 基本结构程序设计在重复的基本操作执行期间,操作数指针( SI与 DI)和操作数寄存器在每一次重复后修改,然而指针将保留重复前缀字节的偏移地址。若一个无重复操作指令,被外部中断源中断,
则在中断返回以后,可以恢复重复操作指令。应避免串操作指令的重复前缀与别的两种前缀同时使用。 CLD指令是 DF标志清零指令,即使 DF=0,将串操作指令设置为自动增量指令。
第 5章 基本结构程序设计
2.利用表实现分支在处理实际问题时,对于分支比较少的情况用
IF_THEN_ELSE结构是最简便可行的,但对于分支很多的情况,
再使用 IF_THEN_ELSE结构实现程序就会变得十分冗长。例如,
编制一个具有建立文件、修改文件、删除文件、显示文件和退出应用程序返回操作系统功能的管理文件的菜单程序,最好不要用 IF_THEN_ELSE结构。在这种情况下,比较好的方法是使用 CASE结构来实现分支。在汇编语言中,通常是使用跳转表法实现 CASE结构。
第 5章 基本结构程序设计具体实现时,需要两个步骤:一是构造成跳转表,二是使用跳转地址、转移指令或关键字实现分支。跳转表存储时可采用连续存储的方法,可将跳转表存储在内存的一片连续单元中,
表中的内容可以是跳转地址、转移指令或关键字等。根据跳转表中存储的内容,将利用表实现分支,即根据表内地址分支,
根据表内转移指令分支或根据表内关键字分支这样三种方法,
如图 5-3所示。
第 5章 基本结构程序设计图 5-3 利用表实现分支及其分类根据关键字分支根据表内指令分支根据表内地址分支表的使用方法跳转表的组成第 5章 基本结构程序设计
1) 根据表内地址分支例 5-9 某工厂有 8种产品的加工程序 R0到 R7分别存放在以
SBR0,SBR1,…,SBR7为首地址的内存中。而这 8个首地址偏移量连续存放在以 BASE为首址的跳转表内。设这 8种产品的编号分别为 0,1,…,7。若现在已知目前要加工的产品编号,
应如何编制一段程序,利用“跳转表”的方法自动转入该种产品的加工程序?
分两个方面来讨论:
(1) 如何构成跳转表?
(2) 如何根据已知的编号从表中查出该种产品加工程序的入口地址,而首要的问题就是要先求出该种产品对应的表项地址。
第 5章 基本结构程序设计图
5-
4
跳转表
SB R 0低位字节
SB R 0高位字节
SB R 1低位字节
SB R 1高位字节

SB R 7低位字节
SB R 7高位字节




M
B A S E
B A S E + 1
B A S E + 2
B A S E + 3

B A S E + 14
B A S E + 15
SB R 0
SB R 1
SB R 7
跳转表第 5章 基本结构程序设计
① 跳转表的组成如图 5-4所示。表开始的第一个单元的地址称作表基地址(或表首地址)。要查找的元素在表中的地址叫表项地址。
如:加工程序 R1的入口偏移地址 SBR1在表中的地址(表项地址)是 BASE+2。不同的加工程序对应有不同的表项地址。
表项地址相对于基地址的偏差字节数称作偏移量。如表项地址 BASE+2相对于表基地址的偏移量是 2。
第 5章 基本结构程序设计
② 表的使用。根据上述分析,可看出:
表项地址 = 表基地址 + 偏移量在这里表基地址是已知的。通过分析表的结构,可看出偏移量由产品编号乘 2求得,因而表项地址就可求出了。由此得到编写程序的算法思想,画出流程图如图 5-5所示。
第 5章 基本结构程序设计图 5-5 表分支流程图分支到相应的加工程序求表地址求偏移量取编号开始结束第 5章 基本结构程序设计程序描述如下:
DATA SEGMENT
BASE DW SBR0,SBR1,SBR2,SBR3
DW SBR4,SBR5,SBR6,SBR7
BN DB? ;产品编号
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,SS∶ STACK
第 5章 基本结构程序设计
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV AL,BN
MOV AH,0
ADD AL,AL ;求偏移量 =产品编号 2
MOV BX,OFFSET BASE ;将表首址送入 BX中
ADD BX,AX ;求表项地址第 5章 基本结构程序设计
MOV AX,[BX] ;将加工程序的入口地址送入 AX中
JMP AX
RET
START ENDP
COSEG ENDS
END START
第 5章 基本结构程序设计
2) 根据表内指令分支表内存放的是转移指令的跳转表,在应用程序中常常要用到。
例 5-10 某监控程序是由 12个子程序组成的,每一个子程序表示一条命令键,这些命令键可以存放在一个跳转表中。这些子程序的入口地址分别为:
执行键子程序入口地址,ADR0
单步键子程序入口地址,ADR1
存储器检查子程序入口地址,ADR5
EPROM编程子程序入口地址,ADR11


第 5章 基本结构程序设计图
5-
6
命令键跳转表

BA SE 0
J M P A D R0
J M P A D R1

J M P A D R5

J M P A D R1 1

第 5章 基本结构程序设计设 12个命令键的编号分别为 0~ 11。跳转表中每 3个单元存放着一条转移指令。分别对应着各命令键的分支转移指令。如果已获取了所按下的命令键的编号 X,并已将其送入寄存器 AL,
那么实现转向相应的命令子程序去执行的程序段可描述如下:
MOV AH,0
MOV BL,AL
ADD AL,AL
ADD AL,BL ;编号乘 3为偏移量
MOV BX,OFFSET BASE0 ;取表首址
ADD BX,AX ;求表地址
JMP BX
第 5章 基本结构程序设计从上述程序可以看出,仍然要根据已知量 (编号 )求表地址。由于每一指令在表中占了 3个单元,所以用编号乘 3得偏移量。跳转表中存放的是转移指令,所以在求出表地址后,
直接转去执行表地址内的指令就可以实现分支了。
第 5章 基本结构程序设计
3) 根据关键字分支这类问题形式可以多种多样,关键字可以是给定的,也可以是在表中的或是表中给出了关键字的地址等等,然后根据关键字的内容分支。
例 5-11 有一台主机为 8台外部设备服务,对于每台外设的服务程序已经编好并已分别存放在以首址为 SR0,SR1,…,
SR7的主机的内存中,每台外设有一条联络线与主机中的寄存器相连,如图 5-7所示。
第 5章 基本结构程序设计图 5-7 系统框图
D7 D6 … D1 D0
寄存器主机
7 号外设 6 号外设 0 号外设第 5章 基本结构程序设计当所有的外设没有提出服务请求时,所有联络线上均为,0”
信号。当其中一台 (且同一时刻只许一台 )外设要求为之服务时,
就在其联络线上发出,1”信号。通过查询主机寄存器中的关键字,就可以得知是哪台外设发出的服务请求。关键字与外设的对应关系如下:
第 5章 基本结构程序设计关键字,D7 D6 D5 D4 D3 D2 D1 D0 外设
0 0 0 0 0 0 0 1 0号外设要求服务
0 0 0 0 0 0 1 0 1号外设要求服务
1 0 0 0 0 0 0 0 7号外设要求服务现在可根据关键字的值转到相应的服务程序去。

编程实现时,仍是先造一张表,表内存放关键字值与其对应的外设服务程序入口地址。如图 5-8所示,表的首地址为
BASE。
第 5章 基本结构程序设计图 5-8 关键字表
0 1 H

BA SE
SR0 ——外设服务程序入口地址

0 2 H

8 0 H
关键字值
SR1 ——外设服务程序入口地址
SR7 ——外设服务程序入口地址对应 0 号外设对应 1 号外设对应 7 号外设第 5章 基本结构程序设计设主机中寄存器的端口地址是 5FH,根据从寄存器中获得的关键字,并利用跳转表实现分支的程序描述如下:
DATA SEGMENT
BADSE DB 1 ;关键字
DW SR0 ;外设服务程序入口地址
DB 2
DW SR1
DB 4
DW SR2
DB 80H
DW SR7

第 5章 基本结构程序设计
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ DATA,SS∶ STACK
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
第 5章 基本结构程序设计
LOP,IN AL,5FH
CMP AL,0
JE LOP
MOV BX,OFFSET BASE
RSH,CMP AL,[BX]
JE BRCH
INC BX
INC BX
INC BX
JMP RSH
BRCH,MOV CX,[BX+1]
JMP CX…
第 5章 基本结构程序设计
SR0,
SR1:
SR7:
START ENDP
CODE ENDS
END START



第 5章 基本结构程序设计
5.4 循环程序设计
5.4.1 重复控制指令该类指令在循环的首部或尾部确定是否进行循环。重复控制指令的目的地址必须在本指令的 -128~ +127字节范围之内,这些指令对标志位无影响,对于串操作及数据块操作是很有用的。
在 80x86中,所有循环程序结构的循环次数计数器均使用
CX/ECX。重复控制指令如表 5-5所示。
第 5章 基本结构程序设计表 5-5 重复控制指令格 式 循环条件 功 能
LOOP LABEL CX←CX -1CX≠0
转移到标号 LABEL处,继续下一次的循环,直到不满足循环条件
LOOPE/LOOPZ LABEL CX←CX -1CX≠0且 ZF=1
转移到标号 LABEL处,继续下一次的循环,直到不满足循环条件
LOOPNE/LOOPNZ
LABEL
CX←CX -1
CX≠0且 ZF=0
转移到标号 LABEL处,继续下一次的循环,直到不满足循环条件说明,① 重复控制指令不影响标志位;
② 每一次执行循环指令后,CX内容自动减 1。
第 5章 基本结构程序设计例 5-12 在 4.4.4节中讲述指令操作数基址变址寻址时,曾举了下述一个例子:
XOR EAX,EAX ; EAX= 0
MOV EBX,OFFSET ARRAYSTR ; EBX=数组 ARRAYSTR的基地址
MOV ECX,LENGTH ARRAYSTR
MOV ESI,0 ;变址寄存器 ESI指向 0
ALAB,ADD EAX,[EBX+ESI] ;利用基址加变址得到数组元素
ADD ESI,4 ;增加变址
LOOP ALAB ;继续第 5章 基本结构程序设计该程序中就用到了循环指令 LOOP。为得到数组元素,可将数组 ARRAYSTR的基地址送到基址寄存器 EBX中,而变址寄存器 ESI初始化时先清 0。每循环一次,只要修改变址寄存器
ESI的内容,即将 ESI增 4,就可得到参与加运算的数组元素了。
第 5章 基本结构程序设计例 5-13 在字节数组中找出第一个非 0数据。
DATA SEGMENT
ARRAY DB 0,0,0,0,0,33,54,18,0,78,26,55
COUNT EQU $-ARRAY
DATA ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
第 5章 基本结构程序设计
START,MOV AX,DATA
MOV DS,AX
MOV CX,COUNT ;数据个数
MOV DI,-1
AGAIN,INC DI
CMP ARRAY[DI],0 ;与 0比较
LOOPZ AGAIN ;相等就循环
MOV DX,DI ;非 0数据的地址
MOV AH,4CH
INT 21H
CODE ENDS
END START
第 5章 基本结构程序设计说明:本程序的构成未采用过程形式描述,返回命令使用的是:
MOV AH,4CH
INT 21H
第 5章 基本结构程序设计例 5-14 在字符串中查找给定的字符,找到显示 Y,否则显示 N。设给定的字符在数据段中给出,例如,需查找字符‘ A’。
DATA SEGMENT
STRING DB 'KKDKTRGPASDFJJFJ'
STR EQU $-STRING
DATA ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
START,MOV AX,DATA
MOV DS,AX
第 5章 基本结构程序设计
MOV CX,STR
MOV SI,-1
MOV AL,'A' ;查找数据送 AL
NEXT,INC SI
CMP AL,STRING[SI] ;比较
LOOPNE NEXT ;不相等就循环
JNZ NOTFOU ;未找到,退出
MOV DL,'Y' ;找到了输出字符 'Y'
MOV AH,2
INT 21H
JMP QUIT
第 5章 基本结构程序设计
NOTFOU,MOV DL,'N' ;未找到输出字符 'N'
MOV AH,2
INT 21H
QUIT,MOV AH,4CH
INT 21H
CODE ENDS
END START
第 5章 基本结构程序设计
5.4.2 循环程序的基本结构
1.循环程序的组成部分循环程序一般由四个部分组成:
(1) 初始化部分:为循环做准备工作,包括建立指针,置计数器,设置其他变量的初始值等;
(2) 循环体:完成循环的基本操作,是循环程序的核心部分;
(3) 修改部分:修改操作数地址等,为下次循环做准备;
(4) 控制部分:修改计数器,查看循环控制条件,进行循环控制。
第 5章 基本结构程序设计
2.循环程序的基本结构形式循环程序的基本结构形式分为“先执行,后判断”结构和
“先判断,后执行”结构。
1),先执行,后判断”结构在这种结构中,进入循环后,先执行一次循环体后,再判断循环是否结束。对“先执行,后判断”结构而言,至少要执行一次循环体,如图 5-9所示。
第 5章 基本结构程序设计图 5-9,先执行,后判断”结构图初始化部分循环体修改部分控制部分
( 循环结束吗? )
N
Y
第 5章 基本结构程序设计例 5-15 试编制一个程序统计一个数据块中负元素的个数。
问题分析:一字节带符号数中,最高位(即符号位)为 1的数为负数。要统计负数个数即查看每一个数的符号位,并统计符号位为 1 的个数。这是有规律地重复,因此,可用循环程序实现。
第 5章 基本结构程序设计
DATA SEGMENT
D1 DB -1,-3,5,6,9,… ;定义若干字节带符号数
RS DW? ;存放负元素
DATA ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ DATA
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
第 5章 基本结构程序设计
MOV AX,DATA
MOV DS,AX
MOV BX,OFFSET D1 ;建数据指针
MOV CX,10 ;置计数器初值
MOV DX,0 ;置结果初值,统计负数的个数值存放在 DX中
LOP1,MOV AX,[BX]
CMP AX,0 ;用 AND AX,AX也可以
JGE JUS
INC DX
第 5章 基本结构程序设计
JUS,INC BX
DEC CX ;循环次数减 1
JNE LOP1
MOV RS,DX
RET
START ENDP
CODE ENDS
END START
第 5章 基本结构程序设计
2),先判断,后执行”结构这种结构,进入循环后,首先判断循环结束的条件,再视判断结果决定是否执行循环体。“先判断,后执行”结构中,
如果一进入循环就满足循环结束条件,循环体将一次也不执行,
即循环次数为零,所以又称为“可零迭代循环”,如图 5-10所示。
第 5章 基本结构程序设计图 5-10,先判断,后执行”结构图初始化部分循环体修改部分
Y控制部分
( 循环结束吗? )
N
第 5章 基本结构程序设计例 5-16 AX寄存器中有一个 16位二进制数,编程序统计其中值为 1的位的个数。统计结果存放在 CX寄存器中。
问题分析:这个程序最好用“先判断,后执行”的结构,
AX寄存器中的数为全 0,则不必再作统计工作了。
从图 5-10看出,一进入循环,首先是控制部分,先进行判断,再看这个程序的循环和控制部分之间有没有明显的分界。
程序段描述如下:
第 5章 基本结构程序设计
5.4.3 多重循环有些问题比较复杂,一重循环不够用,必须使用多重循环,
这些循环是一个套一个的。双重循环程序的一般结构如图 5-11所示。从图 5-11中可以看出,内循环必须完整地包含在外循环中,
循环可以嵌套、并列,但不可以交叉,绝对不允许从外循环中直接跳到内层循环中。
注意:千万不要使循环返回到初始化部分,否则会出现死循环。
第 5章 基本结构程序设计图
5-
11
双重循环程序框图内循环初始化初始化开始内循环体内循环修改部分内 循 环控制部分外循环体外循环修改部分外 循 环控制部分处理结果开始
Y
N
Y
N
第 5章 基本结构程序设计例 5-17 编制计算矩阵向量相乘的程序。比如,
4
3
2
1
4
3
2
1
44434241
34333231
24232221
14131211
c
c
c
c
b
b
b
b
aaaa
aaaa
aaaa
aaaa
计算公式为
1,2,3,4 )(ibaa
4
1j
jij
第 5章 基本结构程序设计展开为
4143132121111 babababac
4243232221212 babababac
4343332321313 babababac
4443432421414 babababac
第 5章 基本结构程序设计使用双重循环在于:计算每一个 ci时,均有 4项,这是一重循环,而 ci共有 4个,这又是一重循环。所以要完成该题,就需要使用双重循环来计算。这就是说,每一个 ci的计算过程都是相同的。
因此可先考虑编制出一个计算 ci(先固定 i=1)的程序,为便于循环,把矩阵 A的元素按行依次相邻存放,即 a11,a12,a13,a14,
a21,a22,a23,a24,a31,…,把向量 B和 C的元素也依次相邻存放,
在数据段里定义数据项如下:
第 5章 基本结构程序设计
A DB a11,a12,a13,a14
DB a21,a22,a23,a24
DB a31,a32,a33,a34
DB a41,a42,a43,a44
B DB b1,b2,b3,b4
C DW 4 DUP(?)
第 5章 基本结构程序设计数据的存储分配如下:
A[0]:a11 A[4]:a21 A[8]:a31 A[12]:a41
A[1]:a12 A[5]:a22 A[9]:a32 A[13]:a42
A[2]:a13 A[6]:a23 A[10]:a33 A[14]:a43
A[3]:a14 A[7]:a24 A[11]:a34 A[15]:a44
B[0]:b1 C[0]:c1
B[1]:b2 C[2]:c2
B[2]:b3 C[3]:c3
B[3]:b4 C[4]:c4
其中,小写字母 a11,a12,…,a44,b1,…,b4等均代表具体的无符号数。
第 5章 基本结构程序设计接下来应考虑 c2的计算。计算 c2和计算 c1有两点不同:一是数据 A从 a21开始,而不是 a11,也就是从 A[4]开始,即 SI从 4
开始而不是从 0开始;二是结果存放在 C[2]中,而不是 C[0]中。
其中,第一点不同,由于在计算 c1的过程中 SI每次加 1,到计算完 c1时,SI的值恰好是 4,这一要求自然满足;第二点不同,可以利用基址寄存器 BX,开始给 BX送初值 0,每循环一次加 2,
利用 C[BX]间接寻址方式访问 ci的方法解决。 c3,c4的计算也是一样的。
第 5章 基本结构程序设计
c2的计算过程可看成是新的循环的初始部分,只是循环控制部分如果都用 LOOP指令,都是用 CX作为计数器的 。 因此需要将控制计算 4个 ci的 CX的计数值暂时保存起来 。 比如,存放在其他此程序不用的寄存器里,一个字存储变量里或堆栈中 。 这里先将它暂时压入堆栈,在使用它之前 ( 执行 LOOP指令前 )
再从堆栈里弹出送回 CX。
第 5章 基本结构程序设计这里出现了一个循环程序的工作部分又是一个循环程序的情况,这就是一重循环套一重循环,称为双重循环。计算一个 ci
的循环叫做内循环;计算所有 ci的循环叫做外循环。对于多重循环,一定要分清层次,内、外循环的四个组成部分应如何划分,
一点也不能模糊。外循环的准备部分包括 0→SI,0→BX 和
4→CX,其中,0→ SI 也是内循环的准备部分;内循环的准备部分同时也是外循环的工作部分,包括 PUSH CX,0→DI,
0→C[BX] 和 4→CX,当外循环重复没有达到 4次时,这些操作被外循环重复执行。如果不加分析地把控制转移出循环,那将是错误的。
第 5章 基本结构程序设计给出一组可以进行计算的具体数据,定义在数据段以 A为起始单元的区域中,计算结果存放在数组 C里。为了程序简便、明了,本例没有写出二进制转化为十进制输出计算结果的指令序列。程序描述如下:
NAME EX
DATA SEGMENT
A DB 1,0,2,3
DB 0,1,1,0
DB 3,0,1,0
DB 4,2,0,1
B DB 0,1,1,0
C DW 4 DUP(?)
TOP DB?
第 5章 基本结构程序设计
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA,SS,STACK
START,MOV AX,DATA
MOV DS,AX
MOV AX,STACK
MOV SS,AX
MOV AX,TOP
MOV SP,AX
MOV SI,0
MOV BX,0
MOV CX,4
第 5章 基本结构程序设计
LOOP1,PUSH CX
MOV DI,0
MOV WORD PTR C[BX],0
MOV CX,4
LOOP2,MOV AH,0
MOV AL,A[SI]
MUL B[DI] ; B[DI]*AL
ADD C[BX],AX ; C[BX]C[BX]+AX
第 5章 基本结构程序设计
INC SI
INC DI
LOOP LOOP2
ADD BX,2 ;确定存放下一个 ci值的地址
POP CX
LOOP LOOP1
MOV AH,4CH
INT 21H
CODE ENDS
END START
第 5章 基本结构程序设计注意:当内、外重循环均要求使用 CX计数器时,可先将外循环计数器 CX的内容压栈,待内循环处理完后,再将外循环计数器 CX的内容弹出栈,用此方法来解决内、外重循环均要求使用 CX计数器而带来的冲突。
第 5章 基本结构程序设计例 5-18 使用冒泡排序法将内存中给定的 10个带符号数按照从小到大的顺序重新排列出来。
分析:算法编制的基本思想是采用两两比较的方法:先拿 an
与 an-1比,若 an>an-1,则不交换,反之则交换;然后用 an-1与 an-2相比,按同样原则决定是否交换,这样一直比下去,最后用 a2与 a1
相比,也按同样原则决定是否交换,当第一次大循环结束时,
数组中的最小值冒到了前面。但是数组尚未按大小排列好,还要进行第二次大循环,这样,数组中的第二个最小值,也上升到顶部 …… 这样不断地循环下去,若数组的长度为 n,则最多经过 n-1次上述的大循环,就可以使数组按大小的次序排列整齐。
在每一个大循环中,数两两比较的次数,在第一次大循环时为 n-
1;在第二次大循环时为 n-2; ……
第 5章 基本结构程序设计依据上述基本思想就可以写出程序了。但在实际中,有的数组不需要经过 n-1次大循环就已经排列整齐了。也就是说,按上述基本思想写出的程序,有时存在不必要的循环,这样就使得程序的效率不高。为了在程序中消除不必要的循环,可设置一个标志,在每次大循环开始时,置此标志为 0;若在整个大循环中,两两比较后,发生过交换,则置此标志为 -1。然后在下一次大循环开始时,检查此标志,若不为 0,表示数组未排列好,
继续进行循环;若为 0,则表示数组已按大小次序排列好 (每次两两比较时,都是大的数在后,小的数在前,故不用交换 ),就停止循环。下面给出的程序就是按这一思想编制的。
第 5章 基本结构程序设计
SORT_DA SEGMENT
ARRAY DW 1273,5346,0FF7FH,1080H,0FFFFH,55ABH
DW 3069H,5C00H,56DEH,0B69H
COUNT EQU $-ARRAY
SORT_DA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ SORT_DA
ASSUME ES∶ SORT_DA,SS∶ STACK
第 5章 基本结构程序设计
STR PROC FAR
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,SORT_DA
MOV DS,AX
MOV ES,AX
MOV BL,0FFH
A1,CMP BL,0
JE A4
XOR BL,BL
MOV CX,COUNT
SHR CX,1
DEC CX
XOR SI,SI
第 5章 基本结构程序设计
A2,MOV AX,ARRAY[SI]
CMP AX,ARRAY[SI+2]
JLE A3
XCHG ARRAY[SI+2],AX
MOV ARRAY[SI],AX
MOV BL,0FFH
A3,INC SI
INC SI
LOOP A2
JMP A1
A4,RET
STR ENDP
CODE ENDS
END START
第 5章 基本结构程序设计需要指出的是,排序是一种非常有用的操作,第 9章介绍的折半查找,其前提就是要求表格中的数据 (或字符 )的排列是有次序的。例如,对于数字,要求它按数字的大小排列,字符则按其 ASCII码值的大小排列。于是对一个无次序的表来讲,
要对其进行折半查找首先要使用某种排序方法,如使用冒泡法对其进行排序。
第 5章 基本结构程序设计
5.4.4 循环控制方法常用的几种循环控制的方法有:
1.用计数法控制循环使用条件:计数次数已知。
使用形式:正或倒计数法。
设计数次数为 n,正计数法的常用指令及格式为:
XOR AX,AX ;或 MOV AX,0等
LOP:
INC AX
CMP AX,n
JNE LOP ;当 ZF= 0时转移


第 5章 基本结构程序设计在正计数法中,计数器 (如 AX)在循环条件外应先清零,然后用 INC改变 AX的值,并使用 CMP作判断。
设计数次数为 n,倒计数法的常用指令及格式为
MOV AX,n
LOP,
DEC AX
JNE LOP
倒计数法在循环之外先给计数器 (如 AX)赋个值 n,然后使用
DEC指令。
只要计数次数事先能确定,用计数法控制循环的方法直观,方便。


第 5章 基本结构程序设计
2.按条件控制循环有些情况下,计数次数无法事先确定,但循环次数与问题中的某些条件有关,这些条件可以检测到,这时采用条件控制循环为好。
使用条件:循环次数与某些条件有关,条件可以检测。
使用形式:检测、比较、判断。
例 5-16中,统计寄存器 AX中值为,1”的个数就属于这种类型的问题。
第 5章 基本结构程序设计因为事先并不知道寄存器的情况,若是全零,已不必再循环;若仅最高位为 1,则移位一次即可;若最低位为 1,则要移位 16次,即循环 16次。循环结束的条件就看寄存器中是否为全 0,
当然对于这个问题来说,也可以采用计数方法。无论什么情况,
都强迫循环进行 16次,不过当 AX为零时,循环 16次统计结果,
,1”的个数仍为 0。这样的问题采用计数方法控制就显得太不合适了。
第 5章 基本结构程序设计例 5-19 求一个数的平方根。
用减奇数次数的方法,求出一个数的近似平方根,这个平方根是一个整数。如求 17的平方根,可以用 17相继减去奇数 1,
3,5,7,…,当结果为负时停止,即
17-1-3-5-7-9<0
可以看出,17在减了 5次奇数后结果变负。可近似认为 17的平方根为 4或 5。在下面的程序中,结果将为 4。
第 5章 基本结构程序设计
DATA SEGMENT
NUM DW 1CE4H
ANS DW?
DATA ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
START,MOV AX,DATA
MOV DS,AX
MOV DX,0H ;存放结果的寄存器清 0
MOV CX,01H ;置第 1个奇数第 5章 基本结构程序设计
AGAIN,SUB NUM,CX ;减去奇数
JL TOEND ;奇数已比持续相减的结果大,退出
INC DX ;减一次奇数,结果增 1
ADD CX,02H ;生成下一个奇数
JMP AGAIN
TOEND,MOV ANS,DX ;平方根送 ANS中
MOV AH,4CH
INT 21H
CODE ENDS
END START
第 5章 基本结构程序设计
3.用逻辑尺控制循环用户输入的一串代码,称为逻辑尺,作为分支的依据。
例 5-20 某程序所需的 12个参数值存于 BUFFER起始的缓冲区中,对 BUFFER中的第 1,2,5,7,10个参数值需调用函数 Y
= 2*X进行计算,对 BUFFER中的第 3,4,6,8,9,11,12个参数值需调用函数 Y= 4*X进行计算。现要求使用一逻辑尺编程实现对 BUFFER中的参数处理。
第 5章 基本结构程序设计问题分析:由于分支的条件不规则,可建立一个与要求相对应的逻辑尺 (位串 )0011010110110000来作为控制循环的条件。
程序如下:
DATA SEGMENT
BUFFER DW 101,202,33,44,55,66,77,808,909,123,678,987;
X的值
BLOCK DW 12 DUP(? ) ; Y的保留单元
LOGRUL EQU 0011010110110000B ;前 12位为逻辑尺,顺序为 1、
2,…,12
DATA ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ DATA
第 5章 基本结构程序设计
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV DX,LOGRUL ;逻辑尺 → DX
MOV CX,12
LEA BX,BUFFER ; BX指向 X
LEA SI,BLOCK ; SI指向 Y
第 5章 基本结构程序设计
AGAIN,MOV AX,[BX] ;取 X
RCL DX,1 ;逻辑尺左移一位 → CF
JC ANOTH ; CF=1,转 ANOTH
CALL FUN1 ; CF=0,调用 FUN1
NEXT,MOV [SI],AX ;保存 Y
INC BX
INC BX ;指向下一个 X
INC SI
INC SI ;指向下一个 Y
LOOP AGAIN
RET
第 5章 基本结构程序设计
START ENDP
CODE ENDS
END START
ANOTH,CALL FUN2 ;调用 FUN2
JMP NEXT
FUN1 PROC ; Y= 2X
ADD AX,AX
RET
FUN1 ENDP
FUN2 PROC ; Y= 4X
ADD AX,AX
ADD AX,AX
RET
FUN2 ENDP
第 5章 基本结构程序设计关于逻辑尺的讨论:
(1) 逻辑尺既不是参与运算的常数,又不是指令,而是判断分支的依据,犹如尺子可以描述布的长短一样。
(2) 可以随意地、方便地改变逻辑尺以实现不同的加工要求。
(3) 逻辑尺可长可短,一个字节或一个字不够用,可用几个连续的存储单元。
(4) 循环结束的控制可以用计数法,可以是固定的次数,也可以是不固定的数。可以用这个数控制循环,也可以利用或设置某些特征条件控制循环。
第 5章 基本结构程序设计
4.用开关变量控制分支循环有些情况下,循环程序内部需有分支,这时可用开关变量控制分支和循环。
使用条件:分支规律已知,计数次数或循环条件已知。
使用形式:条件判断、转移,正、倒计数法。
第 5章 基本结构程序设计
5.5 字 符 处 理
5.5.1 重复操作前缀表 5-6 重复操作前缀指令名称 指令格式 重复条件 指令功能重复操作前缀 REP <串操作指令 > CX≠0
重复执行后面的串操作指令,直到不满足重复条件相等 /为 0时重复操作前缀
REPE/REPZ <串操作指令 > CX≠0且 ZF=1 重复执行后面的串操作指令,直到不满足重复条件不相等 /不为
0时重复操作前缀
REPNE/REPNZ <串操作指令
> CX≠0且 ZF=0
重复执行后面的串操作指令,直到不满足重复条件说明:
① 重复操作前缀不能单独使用,后面必须跟有串操作指令,串操作指令可以是 MOVS,STOS
,LODS,常用的是 MOVSB,MOVSW,而 STOS和 LODS常用于循环中;
② 重复次数计数器使用 CX/ECX,每一次循环后,CX/ECX内容自动减 1。
第 5章 基本结构程序设计
5.5.2 串操作指令
1.串传送指令 MOVS/MOVSB/MOVSW/MOVSD
格式,MOVS OPRD,SRC
MOVSB
MOVSW
MOVSD
第 5章 基本结构程序设计功能:
① MOVS:将 SRC的内容送到 OPRD中,传送长度由 SRC指定。
② MOVSB:将 DS∶ [SI]指定的字节内容传送到由 DS∶ [DI]
所指向的目的地址中。
③ MOVSW:将 DS∶ [SI]指定的字内容传送到由 DS∶ [DI]
所指向的目的地址中。
④ MOVSD:将 DS∶ [SI]指定的双字内容传送到由 DS∶ [DI]
所指向的目的地址中。
第 5章 基本结构程序设计说明:
① 串传送指令不影响标志位;
② 在所有的串操作指令中,如果未显式给出源、目的操作数的地址,则默认源操作数地址为 DS∶ [SI],目的操作数地址为
DS∶ [DI];
③ 若 DF=0,则执行完指令 MOVSB,MOVSW,MOVSD后,
SI,DI内容分别加 1,2,4;若 DF=1,则执行完指令 MOVSB、
MOVSW,MOVSD后,SI,DI内容分别减 1,2,4;
④ 常与重复操作前缀联用,可以将指定长度的字符串由源地址传送到目的地址中,指定的串长度放在重复次数计数器
CX/ECX中。
第 5章 基本结构程序设计
2.串装入指令 LODS/LODSB/LODSW/LODSD
格式,LODS SRC
LODSB
LODSW
LODSD
第 5章 基本结构程序设计功能:
① LODS:将 SRC的内容装入 AL/AX/EAX中,传送长度由
SRC指定。
② LODSB:将 DS∶ [SI]指定的一个字节内容装入 AL中。
③ LODSW:将 DS∶ [SI]指定的一个字内容装入 AX中。
④ LODSD:将 DS∶ [SI]指定的一个双字内容装入 EAX中。
第 5章 基本结构程序设计说明:
① 串装入指令不影响标志位;
② 若 DF=0,则执行完指令 LODSB,LODSW,LODSD后,
SI内容分别加 1,2,4;若 DF=1,则执行完指令 LODSB、
LODSW,LODSD后,SI内容分别减 1,2,4,DI内容不变;
③ 一般不与重复操作前缀联用。
第 5章 基本结构程序设计
3.串存储指令 STOS/STOSB/STOSW/STOSD
格式,STOS OPRD
STOSB
STOSW
STOSD
第 5章 基本结构程序设计功能:
① STOS:将 AL/AX/EAX的内容存到 OPRD中,传送长度由 OPRD指定。
② STOSB:将 AL的内容存到 DS∶ [DI]指定的一个字节单元中。
③ STOSW:将 AL的内容存到 DS∶ [DI]指定的一个字单元中。
④ STOSD:将 AL的内容存到 DS∶ [DI]指定的一个双字单元中。
第 5章 基本结构程序设计说明:
① 串存储指令不影响标志位;
② 若 DF=0,则执行完指令 STOSB,STOSW,STOSD后,
DI内容分别加 1,2,4;若 DF=1,则执行完指令 STOSB、
STOSW,STOSD后,DI内容分别减 1,2,4,SI内容不变;
③ 可以与重复操作前缀联用,结果是将一内存区域连续地赋以同一个值。
第 5章 基本结构程序设计
4.串比较指令 CMPS/CMPSB/CMPSW/CMPSD
格式,CMPS OPRD,SRC
CMPSB
CMPSW
CMPSD
第 5章 基本结构程序设计功能:
① CMPS:将 OPRD的内容与 SRC内容作比较,即用 OPRD
的内容减去 SRC的内容,根据结果置相应的标志位,但 SRC和
OPRD内容不变,比较的字符串长度由 SRC/OPRD指定。
② CMPSB:将 DS∶ [SI]指定的字节内容与 DS∶ [DI]指定的字节内容作比较,即用 DS∶ [SI]指定的字节内容减去 DS∶ [DI]
指定的字节内容,根据结果置相应的标志位,但两个存储单元内容不变。
③ CMPSW:将 DS∶ [SI]指定的字内容与 DS∶ [DI]指定的字内容作比较,即用 DS∶ [SI]指定的字内容减去 DS∶ [DI]指定的字内容,根据结果置相应的标志位,但两个存储单元内容不变。
第 5章 基本结构程序设计
④ CMPSD:将 DS∶ [SI]指定的双字内容与 DS∶ [DI]指定的双字内容作比较,即用 DS∶ [SI]指定的双字内容减去 DS∶ [DI]
指定的双字内容,根据结果置相应的标志位,但两个存储单元内容不变。
说明:
① 串比较指令影响标志位,CF,OF,ZF,SF,AF,PF;
② 若 DF=0,则执行完指令 CMPSB,CMPSW,CMPSD后,
SI,DI内容分别加 1,2,4;若 DF=1,则执行完指令 CMPSB、
CMPSW,CMPSD后,SI,DI内容分别减 1,2,4。
第 5章 基本结构程序设计
5.串扫描指令 SCAS/SCASB/SCASW/SCASD
格式,SCAS OPRD
SCASB
SCASW
SCASD
第 5章 基本结构程序设计功能:
① SCAS:用 AL/AX/EAX的内容减去 OPRD的内容,根据结果置相应的标志位,但结果并不保存,扫描的字符串长度由
OPRD指定。
② SCASB:用 AL内容减去 DS∶ [DI]指定的字节内容,根据结果置相应的标志位,但存储单元内容不变。
③ SCASW:用 AX内容减去 DS∶ [DI]指定的字内容,根据结果置相应的标志位,但存储单元内容不变。
④ SCASD:用 EAX内容减去 DS∶ [DI]指定的双字内容,根据结果置相应的标志位,但存储单元内容不变。
第 5章 基本结构程序设计说明:
① 串扫描指令影响标志位,CF,OF,ZF,SF,AF,PF;
② 若 DF=0,则执行完指令 SCASB,SCASW,SCASD后,
DI内容分别加 1,2,4;若 DF=1,则执行完指令 SCASB、
SCASW,SCASD后,DI内容分别减 1,2,4;
③ 常与操作重复前缀联用,用于扫描内存区域中是否有与
AL/AX/EAX内容相同的串。
第 5章 基本结构程序设计
6.串输入指令 INSB/INSW/INSD
格式,INSB
INSW
INSD
第 5章 基本结构程序设计功能:
① INSB:将寄存器 DX所指定端口的一个字节内容传送到由 DS∶ [DI]所指向的目的地址中。
② INSW:将寄存器 DX所指定端口的一个字内容传送到由
DS,[DI]所指向的目的地址中。
③ INSD:将寄存器 DX所指定端口的一个双字内容传送到由 DS,[DI]所指向的目的地址中。
第 5章 基本结构程序设计说明:
① 串输入指令不影响标志位;
② 若 DF=0,则执行完指令 INSB,INSW,INSD后,DI内容分别加 1,2,4;若 DF=1,则执行完指令 INSB,INSW、
INSD后,DI内容分别减 1,2,4;
③ 与操作重复前缀联用,可用于输入端口指定长度的串。
第 5章 基本结构程序设计
7.串输出指令 OUTSB/OUTSW/OUTSD
格式,OUTSB
OUTSW
OUTSD
功能:
① OUTSB:将 DS∶ [SI]指定的字节内容传送到由寄存器
DX所指定端口中。
② OUTSW:将 DS∶ [SI]指定的字内容传送到由寄存器 DX
所指定端口中。
③ OUTSD:将 DS∶ [SI]指定的双字内容传送到由寄存器
DX所指定端口中。
第 5章 基本结构程序设计说明:
① 串输出指令不影响标志位;
② 若 DF=0,则执行完指令 OUTSB,OUTSW,OUTSD后,
DI内容分别加 1,2,4;若 DF=1,则执行完指令 OUTSB、
OUTSW,OUTSD后,DI内容分别减 1,2,4;
③ 与操作重复前缀联用,可用于输出内存区域中指定长度的串。
第 5章 基本结构程序设计
5.5.3 字符处理程序设计举例例 5-21 使用 CMPS指令,编制一个比较两字符串的程序。
分析:相等的两个字符串是指字符串的长度相同且对应字符相同,简称字符串相等。若两个字符串的长度不同,则它们必然不相等,因此判断两个字符串是否相等可首先判断这两个字符串的长度是否相等,若相等再判断对应字符是否相同。因此,在程序开始处先比较两字符串的长度是否相等,若相等,再逐个字符进行比较。
第 5章 基本结构程序设计由于是对字符串实施操作,编程时可首先想到使用串操作指令。如果一个字符串用 SI作为指针来指示,另一个字符串用
DI作为指针来指示,若两字符相等,则同时相应地修改指示两个字符串的串指针 SI和 DI,以指向串中的下一个元素。这就实现了检查两个字符串是否相等的功能,CMPS指令可以用来检查两个串是否相同。因此,可选用 CMPS指令。编写程序时,
可使用循环结构,也可使用重复前缀 REPZ。编写程序描述如下:
第 5章 基本结构程序设计
MY_DATA SEGMENT
STRING1 DB 'THIS IS A STRING1' ;定义字符串 1
STRING2 DB 'THIS IS A STRING2' ;定义字符串 2
COUNT EQU $-STRING2
RESULT DB?
MY_DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
第 5章 基本结构程序设计
ASSUME CS:COSEG,DS:MY_DATA
ASSUME ES:MY_DATA,SS:STACK
FH PROC FAR
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,MY_DATA
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET STRING1 ;字符串 1首地址送 SI中
MOV DI,OFFSET STRING2 ;字符串 2首地址送 DI中第 5章 基本结构程序设计
MOV CX,COUNT ;字符串长度送 CX中
CLD ;将 DF标志位清 0,地址递增
REPZ CMPSB ;重复比较两字符串的每一位,如果有不 相同的,则退出
JNZ UNMAT ; CX不为 0时转移
MOV AL,0 ;比较的两字符串相同
JMP OUTPT
UNMAT,MOV AL,0FFH ;比较的两字符串不相同
OUTPT,MOV RESULT,AL ;保存比较结果
RET
FH ENDP
COSEG ENDS
END START
第 5章 基本结构程序设计说明,CMPS指令加上前缀 REPE或 REPZ意为:“当串未结束 (CX≠0)且串是相等 (ZF标志为 1)时继续比较”; CMPS指令加上前缀 REPNE或 REPNZ则意为:“当串未结束 (CX≠0)且串不相等 (ZF标志为 0)时继续比较”。
第 5章 基本结构程序设计例 5-22 利用 SCAS指令对指定的字符串进行搜索。
分析:把要搜索的关键字放在 AL(字节 )或 AX(字 )中,程序用以搜索内存的某一数据块或字符串中有无此关键字? 若有,记录搜索次数 (若次数为 0,表示无搜索的关键字 )和存放关键字的地址。
程序一开始要设置数据块的地址指针 (SCAS指令要求设在 DI
中 ),要设立数据块的长度 (要求设在 CX中 ),把关键字送入 AL中或 AX中。搜索可以用循环程序或利用重复前缀,用 ZF标志判断是否搜索到,以便分别处理。
第 5章 基本结构程序设计
BUF_DAT SEGMENT
CHAR EQU '$'
PTRN DB 'THIS IS A EXAMPLE $' ;定义一个字符串
COUNT EQU $-PTRN ;计算字符串长度
BUF_DAT ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS:COSEG,DS:BUF_DAT
ASSUME ES:BUF_DAT,SS:STACK
第 5章 基本结构程序设计
BEG PROC FAR
BEGIN,PUSH DS
MOV AX,0
PUSH AX
MOV AX,BUF_DAT
MOV DS,AX
MOV ES,AX
MOV DI,OFFSET PTRN
MOV AL,CHAR ;将要扫描的字符送 AL中
MOV CX,COUNT ;字符串长度送 CX中
CLD ;将 DF标志位清 0,地址递增
REPNE SCASB ;扫描字符串
JZ PASTPR
MOV DI,0 ;没有找到该字符第 5章 基本结构程序设计
PASTPR,DEC DI ;找到该字符,DI中存放该字符的偏移地址
RET
BEG ENDP
COSEG ENDS
END BEGIN
第 5章 基本结构程序设计例 5-23 内存中以 BUFR单元开始的区域连续存放着一个
ASCII字符串,编程统计其中包括多少个字符串,AM”,将统计的个数以十进制形式输出到显示器上。
分析:这实际上是串的模式匹配问题。内存中以 BUFR单元开始的区域连续存放着一个 ASCII字符串称为主串,子串,AM”
称为模式。主串和模式分别用 s,t表示。当子串 t和主串 s匹配成功时,计数器加 1。子串 t和主串 s中所有的字符比较完后,计数器中的值就是主串 s中包含子串 t的数目了。
第 5章 基本结构程序设计算法的基本思想是:从主串 s的第一个字符起和模式的第一个字符比较,若相等,则继续逐个比较后续字符,否则从主串的第二个字符起再重新和模式的字符比较。依此类推,直至模式 t中的每个字符依次和主串 s中的一个连续的字符序列相等,则称匹配成功,计数器实施加 1的操作,否则称匹配不成功,计数器值为零。
值得指出的是,当找到字符‘ A’后,若下一个字符不是‘ M’
时,字符串指针不能加 1,而是应在字符‘ A’后再找‘ A’,以免漏掉字符串‘ AAM’的情况。
第 5章 基本结构程序设计
DATA SEGMENT
BUF DB 'KFAMAMAAAQAWSAMYTRAMEAAAMYYMAMAMAMJKF'
COUNT EQU $-BUF
BUF1 DB 3 DUP(' ')
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
ASSUME SS:STACK,ES:DATA
第 5章 基本结构程序设计
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET BUF ;将源字符串的首地址送 SI中
MOV CX,COUNT ;字符串长度送 CX中
MOV BX,0
MOV AH,0
第 5章 基本结构程序设计
LOP1,MOV AL,[SI]
CMP AL,'A' ;比较字符 'A'
JNZ SR0 ;不是则比较下一个
INC SI
DEC CX
JZ OK ;是否到源字符串结尾
MOV AL,[SI]
CMP AL,'M' ;比较字符 'M'
JNZ LOP1 ;不是则比较是否为字符 'A'
MOV AL,BL
ADD AL,1 ;是则将计数器加 1
DAA
MOV BL,AL
第 5章 基本结构程序设计
SR0,INC SI
LOOP LOP1
OK,MOV DI,OFFSET BUF1
MOV DL,BL ;将统计的数字转变为 ASCII码存入存储区
SHR BL,1
SHR BL,1
SHR BL,1
SHR BL,1
MOV AL,30H
ADD AL,BL
MOV [DI],AL
第 5章 基本结构程序设计
INC DI
AND DL,0FH
ADD DL,30H
MOV [DI],DL
INC DI
MOV AL,'$'
MOV [DI],AL
MOV DX,OFFSET BUF1 ;输出统计的数字
MOV AH,9
INT 21H
RET
START ENDP
CODE ENDS
END START
第 5章 基本结构程序设计习 题 五
5.1 编制计算符号函数的程序。
5.2 某软件共可接收 10个键盘命令 (分别为 A,B,C,…,
J),完成这 10个命令的程序分别为过程 P0,P1,…,P9。编程序从键盘接收命令,并转到相应的过程去执行。要求用两种方法:
(1) 用比较、转移指令实现。
(2) 用跳转表实现。
第 5章 基本结构程序设计
5.3 设从 STRING开始存放一个字符串,统计字符串中字符
‘ A’的个数,并将结果存放在 RESUL字节单元中,且以十六进制形式将结果输出。
5.4 设从 BUFF开始存放若干带符号字节的数据,将它们相加且将结果 (超过一个字节的范围 )存放到字单元 SUM中。
5.5 将两个多字节压缩 BCD码相加,假定两个非压缩 BCD
码分别从 BCD1,BCD2开始存放,结果从 BCD3开始存放。
第 5章 基本结构程序设计
5.6 设从 STR开始存放一个以#为结束标志的字符串,把字符串中的字符进行分类,数字字符送入 NUM开始的内存区中,
大写字母送入 BCHAR开始的内存区中,小写字母存入 LCHAR
开始的内存区中,其他字符存入 OTHER开始的内存区中。
5.7 内存自 BUFF单元开始的缓冲区连续存放着 1000个学生的英文分数,编程序统计其中 90~ 100,60~ 89,60分以下各有多少人,并把结果连续存放到自 RESULT开始的单元 (各段定义要求完整 )。
5.8 编写程序,找出首地址为 BUFF的包含 100个带符号字节数据的数据块中的最小偶数,并以十六进制形式显示在屏幕上。
第 5章 基本结构程序设计
5.9 在首地址为 TABLE的字数据块中存放按升序排列的若干带符号数,编写程序,把出现次数最多的数及出现次数分别存入
RESUL1,RESUL2字单元中。
5.10 已知数据块 BUFFA中存放 15个互不相等的字节数据,
BUFFB中存放 20个互不相等的字节数据,编写程序,将既在
BUFFA中出现,又在 BUFFB中出现的数据存放到 BUFFC开始的缓冲区中。
5.11 输入一个字符串并以回车作为结束,将其排序后输出到屏幕上。
5.12 设从 BUFFER开始存放若干带符号字节数据,编写程序,
将其中的正数按由大到小的顺序存入 PLUS开始的缓冲区中。