单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,精品,*,本章学习要点:,(1)子程序的编写格式,(2)子程序调用时的参数传递方法,(3)嵌套及递归子程序,一、过程定义语句(,proc,ess),利用过程定义伪指令语句,可把程序片段说明为具有近类型或远类型的过程,并且能给过程取一个名字。,过程定于语句的格式如下:,过程名,PROC,NEAR|FAR,过程名,ENDP,过程的类型在过程定义开始语句PROC中指定;,过程可以被指定位近(NEAR)类型,也可以被指定为远类型。如果不指定,则通常默认为近类型;,定义一个过程的开始语句PROC和结束语句ENDP前使用的过程名称必须一致,从而保持配对。,精品,本章学习要点:精品,1,像普通标号一样,,过程名具有段值、偏移和类型这三个属性,。,过程名的段值和偏移是对应过程入口,(过程定义开始伪指令语句后的指令语句),的段值和偏移,。,例:下面程序片段运行后,AL=?,BL=?。,XOR AL,AL,CALL SUBS,MOV BL,AL,CALL SUBS,RCR AL,1,HLT,;停机,halt,SUBS PROC NEAR,NOT AL,JS NEXT,STC,;CF=1,S,e,T C,f =1,NEXT:RET,SUBS ENDP,精品,像普通标号一样,过程名具有段值、偏移和类型这三个属性。精品,2,例:用程序调用的方法,完成一个把16位二进制数转换为4位十六进制ASCII码的转换程序。,子程序说明:入口参数:DX=欲转换的二进制数;,DS:BX=存放转换所得ASCII码串的缓冲区首地址,转换后的ASCII码串按照高位到低位的次序存放在指定的缓冲区中。,HTASCS PROCRET,MOV CX,4HTASCS ENDP,HTASCS1:ROL DX,1,HTOASC PROC NEAR,ROL DX,1,AND AL,0FH,ROL DX,1,ADD AL,30H,ROL DX,1,CMP AL,39H,MOV AL,DL,JBE HTOASC1,CALL HTOASC,ADD AL,7,MOV BX,AL,HTOASC1:RET,INC BX,HTOASC ENDP,LOOP HTASCS1,精品,例:用程序调用的方法,完成一个把16位二进制数转换为4位十,3,二、主程序与子程序间的参数传递,主程序在调用子程序时,往往要向子程序传递一些参数;同样地,子程序运行后夜经常要把一些结果传会给主程序。主程序和子程序之间的这种信息传递称为参数传递。,有多种参数传递的方法:,(1)寄存器传递法,(2)约定内存单元传递法,(3)堆栈传递法,(4)其它方法,1.利用寄存器传递参数,利用寄存器传递参数就是把参数放在约定的寄存器中。这种方法适用于传递参数较少的情况。,精品,二、主程序与子程序间的参数传递精品,4,例:写一个大写字母转换为小写字母的子程序,;子程序名:UPTOLW,;功能:大写字母转换为小写字母,;入口参数:AL=字符的ASCII码,;出口参数:AL=字符的ASCII码,;说明:如字符为大写字母,则转换为小写,其它字符不变。,UPTOLW PROC,PUSHF;保护各标志,CMP AL,A,JB UPTOLW1,CMP AL,Z,JA UPTOLW1,ADD AL,20H,UPTOLW1:,POPF;恢复各标志,RET,UPTOLW ENDP,精品,例:写一个大写字母转换为小写字母的子程序精品,5,2.利用约定存储单元传递参数,在传递参数较多的情况下,可利用约定的内存变量来传递参数。,例:写一个实现32位数相加的子程序,;子程序名:MADD,;功能:32位数相加,;入口参数:DATA1和DATA2缓冲区中分别存放要相加的数,;出口参数:DATA3缓冲区存放结果,;说明:,;(1)32位数据的存放次序采用“高高低低”原则,;(2)可能产生的进位放在DATA3开始的第5字节中,精品,2.利用约定存储单元传递参数精品,6,MADD PROC,PUSH,AX,;为什么会把AX,CX,SI压入栈?,PUSH,CX,PUSH,SI,MOV,CX,2,XOR SI,SI,;CF也会被清0,MADD1:MOV,AX,WORD PTR DATA1SI,ADC,AX,WORD PTR DATA2SI,MOV WORD PTR DATA3SI,AX,INC SI,INC SI,POP,SI,LOOP MADD1,POP,CX,MOV AL,0,POP,AX,ADC AL,0RET,MOV BYTE PTR DATA3,+4,AL MADD ENDP,精品,MADD PROC精品,7,3.利用堆栈传递参数,(1)如果利用堆栈传递入口参数,,那么主程序在调用子程序之前,把需要传递的参数依次压入堆栈,子程序从堆栈中取入口参数,;,(2)如果使用堆栈传递出口参数,那么,子程序返回前,把需要返回的参数存入堆栈,主程序在堆栈中取出口参数,。,例:写一个测量字符串长度的子程序,设字符串以0为结束标志。,;子程序名:STRLEN,;功能:测量字符串长度,;入口参数:字符串起始地址的段值和偏移放在堆栈中,;出口参数:AX=字符串长度。,精品,3.利用堆栈传递参数精品,8,STRLEN PROC,PUSH BP,MOV BP,SP,PUSH DS,PUSH SI,MOV DS,BP+6,MOV SI,BP+4,MOV AL,0,STRLEN1:CMP AL,SI,JZ STRLEN2,INC SI,JMP STRLEN1POP DS,STRLEN2:MOV AX,SIPOP BP,SUB AX,BP+4RET,POP SI STRLEN ENDP,精品,STRLEN PROC精品,9,主程序调用这个子程序的代码片段如下:,MOV AX,SEG STR,PUSH AX,MOV AX,OFFSET STR,PUSH AX,CALL STRLEN,MOV LEN,AX,当然,除了上面提及的3种方式外,,如果过程和调用程序在同一文件(同,一程序块中,则过程可直接访问模块,中的变量。,精品,主程序调用这个子程序的代码片段如下:精品,10,随着指令的丰富、子程序的引入,汇编语言的表达也越来越灵活。为了方便地组织数据,引入了,结构伪操作STRUC,。,STRUC可以把不同类型的数据放在同一个结构里,方便处理。,a).结构类型说明格式为:,structure_name STRUC,;DB、DW、DD等伪操作,structure_name ENDS,注意:,ENDS之前为结构名,注意与段结束相区别,。,例如:下列语句说明了一个名STUDENT的结构类型:,STUDENT STRUC,ID DW?,SCORE DB 0,NAME DB ABCDEFGH,STUDENT ENDS,但是,定义一个结构类型的时候不进行任何存储器分配,只有在定义结构变量时才进行存储分配。,精品,随着指令的丰富、子程序的引入,汇编语言的表达也越来越灵活。,11,b).结构变量的定义,格式是:,变量名 结构名 ,例:Lisi STUDENT ;三个字段重新赋值,Wangwu STUDENT ;字段SCORE仍用缺省值,Zhangsan STUDENT ;三个字段均用缺省初值,Team STUDENT 50 DUP();定义50个结构变量,初值不变,在定义结构变量时,如果某个字段有多值,就不能给该字段重新赋初值(定义时存在“DUP”,“,”等)。,c).访问方式,访问方式:结构变量名.结构字段名,该变量的地址实质少年宫是结构变量地址的偏移与相应字段偏移值之和。,例:Zhangsan.ID;访问张三的学号,实际上是,直接寻址,还可以把结构变量地址的偏移先存入某个基址或变址寄存器,然后利用“寄存器名”来代替结构变量名。,例如:MOV BX,OFFSET Zhangsan,MOV AL,BX.SCORE,精品,b).结构变量的定义精品,12,例:通过结构类型,在主程序和子程序中传输信息。,精品,例:通过结构类型,在主程序和子程序中传输信息。精品,13,三、嵌套与递归子程序,一个子程序可以作为调用程序去调用另外一个子程序,这种情况称为,子程序的嵌套,。,嵌套的层数称为,嵌套深度,。,深度为2的嵌套,精品,三、嵌套与递归子程序深度为2的嵌套精品,14,如果一个子程序直接调用它自身,这种调用称为,(直接)递归调用,。,具有递归调用的子程序就称为递归子程序。,递归是嵌套的特殊情况。,精品,如果一个子程序直接调用它自身,这种调用称为(直接)递归调用,15,递归子程序的设计要点:,(1)递推性:逐级调用;,(2)回归性:逐层回归;,(3)有穷性:终止条件;,这3点为所有语言递归程序设计具有的共性。,汇编语言设计递归程序时的个性在于:,(1)参数和中间结果一般存于堆栈中,但有时也可以存于寄存器中;,(2)递归的深度受堆栈空间的限制。,精品,递归子程序的设计要点:精品,16,例:子程序FACT采用递归算法实现阶乘。,;子程序名:FACT,;功能:计算n!,;入口参数,:(AX)=n,;出口参数:(AX)=n!,;说明:(1)采用递归算法实现阶乘;,;(2)n 不能超过8,FACT(n)=n*FACT(n-1)=n*(n-1)*FACT(n-2),当n=0时,FACT(0)=1.,要点:,(1)递推:只要n不为0,即推进到FACT(n-1);,(2)有穷:n=0时有确切解,即FACT(0)=1,(3)回归:逐层返回FACT(n-1)的解和n(保存的中间参数),精品,例:子程序FACT采用递归算法实现阶乘。精品,17,FACT PROC,PUSH DX,;保存中间参数(最外层为原有参数),MOV DX,AX,CMP AX,0,;判断n是否为0?,JZ DONE,;如是,则终止推进。(有穷),DEC AX,;否则,继续推进,CALL FACT,;推进,MUL DX,;中间结果后逐层返回:n*FACT(n-1),POP DX,;得到中间参数(最外层为原有参数),RET,DONE:MOV AX,1,;给出确定结果 0!=1,POP DX,;得到中间参数,RET,FACT ENDP,精品,FACT PROC精品,18,四、综合示例,有10个学生的成绩分别为76、6980。编制一个子程序分别统计6069分,7079分,8089分,9099分及100分的人数,分别存放到S6,S7,S8,S9,S10单元中。,DSEG SEGMENT,REC DW 76,69,63,83,92,73,65,100,99,80,S6,DW 0,S7,DW 0,S8,DW 0,S9,DW 0,S10,DW 0,DSEG ENDS,STACK SEGMENT,DW 64 DUP(?),STACK ENDS,精品,四、综合示例精品,19,CODE SEGMENT,MAIN PROC,FAR,ASSUME CS:CODE,DS:DSEG,SS:STACK,START:,PUSH DS,SUB AX,AX,PUSH AX,MOV AX,DSEG,MOV DS,AX,MOV CX,10,CALL COUNT,;调用COUNT子程序进行统计,;可在此处添加显示输出,RET,MAIN ENDP,注意:,红色部分在这里构成一种固定搭配,把主程序看成DOS调用的远过程,RET与前2个PUSH配对,,相当于:,MOV AH,4CH,INT 21H,精品,CODE SEGMENT精品,20,COUNT PROC NEAR,;主程序和子程序位于同一,MOV SI,0,;模块,所以变量可共享。,NEXT:MOV AX,RECSI,MOV BX,10,DIV BL;,商位于AL中,CBW,MOV BX,AX,SUB BX,6,SAL BX,1,INC S6BX,ADD SI,2,LOOP NEXT;,循环次数由CX控制(主程序设置),RET,COUNT ENDP,CODE ENDS,END START,精品