已阅读5页,还剩47页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第11章子程序结构程序设计11 1概述11 2子程序的结构形式11 3子程序设计方法 11 4子程序设计举例11 5DOS系统功能调用 11 1概述采用子程序结构的优点 1 简化了程序设计过程 使程序设计时间大量节省 2 缩短了程序的长度 节省了程序的存储空间 3 增加了程序的可读性 使程序更加清晰 便于对程序的修改与调试 4 方便了程序的模块化 结构化和自顶向下的程序设计过程 11 2子程序的结构形式一个完整的子程序结构形式 主要包括以下几个方面的内容 子程序说明文件一般子程序是以子程序文件的形式存在 子程序文件又由文字说明和子程序本身两部分构成 子程序文字说明为子程序的使用者提供足够的信息 使程序员不需查看子程序的内部结构或者程序本身 就可以决定是否选用它 子程序说明文件一般应包含以下几项的内容 子程序名 一般取具有顾名思义的标识符 子程序的功能 说明子程序要完成的具体任务 子程序所选用寄存器名 存储单元的分配情况 子程序的入口参数 说明子程序运行中所需要的参数及存放位置 子程序的出口参数 说明子程序运行结束后的结果参数及存放位置 子程序示例 通过所举示范性的例子 把具体的参数值代入 使之更具体了解子程序的功能 并且还能起到验证的作用 例如 有一个子程序说明文件为 子程序名 DCB 功能 完成将一字节的压缩BCD码转换成二进制数 输入参数 AL寄存器中存放要转换的压缩BCD码 输出参数 CL寄存器中存放转换后的二进制数 要使用的寄存器 AX BX CX 示例 输入AL 01101001B 69H代表十进制数69编码 输出CL 01000101B 十进制数69的二进制编码 子程序的现场保护和现场恢复在编写子程序时 要选用各种寄存器 有些寄存器在调用子程序前 可能已被使用过 并且在执行完子程序返回后 仍然要用到这些寄存器的内容 这样主程序与子程序在寄存器的使用上就有可能发生冲突 因此 就出现了如何保护寄存器的问题 也就是现场保护和现场恢复的问题必须妥善解决 如果调用程序 主程序 在调用子程序之前 所有寄存器都属于空闲待用状态 在这种情况下 就没有必要考虑寄存器的保护问题 只要正确安排哪些寄存器作为入口参数或出口参数即可 如果寄存器不空闲 后续指令还使用这些寄存器中的内容 则就要考虑对其施加保护 需要保护的寄存器 它将在子程序中被使用 而返回到调用程序后仍然需要使用其原有内容的那些寄存器 即保护调用程序和子程序两者在使用上发生冲突的那些寄存器 但在编程时 一时很难弄清哪些是有冲突的寄存器 一种较为简单的方法是把所有的寄存器加以保护 在什么地方保护 是在主程序中保护 还是在子程序中保护 是编写带有子程序的程序时应该认真考虑的一个问题 通常情况下在子程序中进行寄存器保护较好 特别是作为一个通用子程序 使用者并不一定了解子程序中将使用了哪些寄存器 若由主程序来保护 在未对子程序做深入了解时 难免带有盲目性 因此在这种情况下寄存器的保护工作应由子程序来承担 即在子程序的开始部分 先进行相关寄存器 主要是在子程序中使用的各寄存器的保护 然后再进行子程序的处理操作 在执行完子程序后 返回前 先恢复各相关寄存器内容后 再执行返回指令 返回到断点处继续执行被打断的程序 如果在主程序中进行保护 应对在主程序中使用过 在调用主程序返回后仍然要使用原有信息的那些寄存器进行保护 然后再调用子程序 在从子程序返回后 再恢复各寄存器内容 从而不会破坏原来程序对寄存器的使用要求 从以上分析可知 保护现场和恢复现场的工作既可在主程序中完成 也可在子程序中完成 这可根据用户在程序设计时自行安排 如果子程序设计时 未考虑保护主程序的现场 则可在主程序调用子程序前进行保护现场 从子程序返回后恢复现场 通常在主程序中保护现场 就一定在主程序中恢复 在子程序中保护现场则一定要在子程序中恢复 这样安排 程序结构清楚 使用方便 不易出错 1 利用堆栈保护现场与恢复现场利用进栈指令PUSH 将寄存器的内容保存在堆栈中 恢复时再用出栈指令POP从堆栈中弹出 这种方法较为方便 尤其在设计嵌套子程序和递归子程序时 由于进栈和出栈指令会自动修改堆栈指针 保护和恢复现场层次清晰 只要注意堆栈操作的先进后出的特点 只要正确使用进出栈指令 就不会引起出错 这是一种常用方法 SUB1PROCNEARPUSHAX PUSHBX 保护现场PUSHCX PUSHDX 子程序处理POPDX POPCX 恢复现场POPBX POPAX RETSUB1ENDP 现场保护和现场恢复常采用的方法 2 利用内存单元保护现场与恢复现场利用数据传送指令将主程序所占用的寄存器内容保存到指定的内存单元中 恢复现场时再用数据传送指令 读操作 从指定的内存单元中取回到对应的寄存器中 这方法使用时不太方便 故较少使用 BUFDW10HDUP SUB1PROCNEARMOVDI OFFSETBUFMOV DI AX 保护现场MOV DI 2 BXMOV DI 4 CXMOV DI 6 DX LEASI BUF 恢复现场MOVAX SI MOVBX SI 2 MOVCX SI 4 MOVDX SI 6 RETSUB1ENDP 3 利用寄存器保护现场与恢复现场在主程序与子程序中 能够发生冲突的寄存器较少 且有富余待选用的寄存器时 可利用这些待用寄存器保护现场与恢复现场 如BP寄存器为待用 主 子程序中发生冲突寄存器仅为AX 就可利用BP来保护与恢复 SUB1PROCNEARMOVBP AX 保护AX的内容 MOVAX BP 恢复AX的内容RETSUB1ENDP 子程序的调用和返回在程序设计时 为了使程序的结构清晰 增加可读性 一般都用过程 子程序 定义语句 PROC ENDP 将子程序定义为独立的程序段 并说明是NEAR类型还是FAR类型 具有NEAR类型的子程序中的RET指令 汇编成段内 近 返回指令 它不能被其它代码段的程序调用 要使子程序既可以被本代码段的程序调用 又可被其它代码段的程序调用 该子程序必须在过程定义语句中被说明为FAR类型属性 其返回指令RET将被汇编成段间 远程 返回指令 段内与段间返回指令RET的机器代码不同 子程序段内调用和返回一个段内调用的子程序 可直接定义在代码段中 如果有多个子程序 都是段内调用 可以在代码段中任意位置定义它们 可置于主程序前面或放在主程序后面都是允许的 但是将它们放在主程序中间 就必须注意主程序指令之间的连接关系 否则就很容易出错 例 子程序及其调用之例 要求 在A B字节单元中各存有一个无符号数 完成二个无符号数的加法及减法运算 并将其结果在屏幕上以十进制数形式显示 要求用子程序编写加 减运算以及二进制到十进制数转换的程序 注 本例要求实现的加 减运算及二进制数转换成十进制数显示的程序段 都是很容易编写的 其目的就在于利用很简单的例子来了解主程序对子程序的调用关系 为方便起见 假定两数相加或相减 其结果都为二位正的十进制数 DATASEGMENTADB66BDB28CDB 存加数的和DDB 存差DATAENDSSTAKSEGMENTSTACKDW50DUP STAKENDSCODESEGMENTASSUMECS CODE DS DATA START MOVAX DATAMOVDS AXLEASI ALEADI BCALLSADD 调用加法子程序CALLOUTD 调用显示子程序CALLSSUB 调用减法子程序CALLOUTDMOVAH 4CHINT21H 主程序返回DOS SADDPROCNEAR 加法子程序 过程 MOVAL SI ADDAL DI MOVC AL 存和数RETSADDENDP SSUBPROCNEAR 减法子程序 过程 MOVAL SI SUBAL DI MOVD AL 存差RETSSUBENDP DISPPROCNEAR 显示单字符子程序ORDL 30HMOVAH 2INT21HRETDISPENDP OUTDPROCNEARMOVAH 0MOVBL 10DIVBLMOVDL AL 显示十位数MOVDH AH 暂存个位数CALLDISPMOVDL DHCALLDISPMOVAH 2MOVDL 0DH 回车INT21HMOVDL 0AH 换行INT21HRETOUTDENDPCODEENDSENDSTART 子程序段间调用和返回段间调用的子程序 过程 必须定义成FAR类型 调用FAR类型子程序的CALL指令 在保存断点 返回地址 时不仅要保存断点的偏移地址IP 而且代码段的段基值CS也要保存 当执行指令RET返回时 要将断点的偏移地址与段基值分别送入IP与CS 段间调用和返回所使用的CALL和RET指令能够自动实现上述操作 用户不必为此操心 子程序的段间调用 多用于不同模块之间的调用 而在同一模块中 通常只设一个代码段 只要用段内调用就可以了 但若同一模块被设计成多个代码段 则过程名仍须定义为FAR类型 编制不同模块的段间调用 需要解决的问题是 调用过程的程序段和定义过程的程序段 即子程序 通常它们分别处在不同的代码段中 所以不同的模块应该单独汇编 再经连接程序连接 才能将它们组合在一起 调用程序段所调用的外部过程名必须用EXTRN伪指令在代码段内进行说明 并指明它们的类型属性 而过程所在的程序段中 必须用PUBLIC伪指令对提供给其它段调用的过程名进行公用说明 这两个伪指令所说明的过程名 标号名及变量名 在汇编时 汇编程序将根据这些说明才能进行有效的连接 并产生段间调用的CALL和RET指令代码 由连接程序 LINK 连接后 就最终将它们之间的关系正式连接在一起了 这样才可以实现子程序的段间调用 例 段间调用示例 将非压缩BCD码转换成ASCII码并送显示 编程要求 从字节变量DAI开始存放30个非压缩的BCD码 设高4位为零 把它们转换成ASCII码存于变量DA2为首址的字节单元中 并将转换后的字符显示在屏幕上 这个问题本来不需要使用段间调用的形式编程 就是因为问题简单也好理解 所以采用段间调用的形式进行编程 更好体会段间调用的程序结构 NAMESUBPRGEXTRNDA1 BYTE 外部引用变量说明CODE2SEGMENTPARA Code ASSUMECS CODEPUBLICSPRG 定义公用名SPRGPROCFAR BCD码转换成ASCII码的子程序MOVAL DA1 SI ADDAL 30HRETSPRGENDPCODE2ENDSEND 此处END后不可有标号或过程名 NAMEBCDASCDATASEGMENTDA1DB8 6 4 7 共30个非压缩BCD码DA2DB30DUP 存放转换后的ASCII码COUNTEQU30 非压缩BCD码个数DATAENDSSTAKSEGMENTSTACKDW100DUP STAKENDSPUBLICDA1 定义变量DA1为公用名EXTRNSPRG FAR 说明SPRG是外部的且为段间属性CODE1SEGMENTPARA Code ASSUMECS CODE1 DS DATASTART MOVAX DATAMOVDS AX MOVDI 0 采用变址寻址的初始化方式MOVSI 0MOVCX COUNTLOP CALLSPRG 段间调用BCD码转ASCII码程序MOVDA2 DI AL 存转换后的ASCII码INCDIINCSIMOVDL AL 显示结果MOVAH 2INT21HMOVDL 显示空格 以便分开每次显示结果LOOPLOPMOVAH 4CHINT21HCODE1ENDSENDSTART 11 3子程序设计方法子程序的定义关于子程序的定义前面已多次提到 这里不妨再进一步说明 子程序是通过过程定义伪指令PROC ENDP来定义的 不仅要指名过程名 而且还要指出其类型属性 NEAR或FAR 同时在PROC和ENDP之间给出该子程序应完成指定功能的程序段 其执行的最后一条指令是RET返回指令 子程序 过程 定义的一般格式为 ProcedurenamePROCAttribute ProcedurenameENDP其中过程名为标识符 又是子程序入口的符号地址 它的写法和标号的写法相同 属性 Attribute 是指类型属性 它可以是NEAR 默认 或FAR 根据属性指出对该子程序的调用是段内的调用还是段间的调用 其相应的返回也一定是段内返回或段间返回 我们只须在子程序定义时考虑其属性 而CALL和RET的属性由汇编程序来断定 不必用户去处理 定义子程序类型属性的原则是 1 主程序和被调用的子程序在同一个代码段中 则子程序定义说明其为NEAR属性或不写 默认的类型属性 2 主程序和被调用的子程序不在同一个代码段中 则把子程序定义说明其为FAR属性 远程属性 3 一般亦可将主程序定义为主过程 主过程应为FAR属性 因为我们将程序的主过程看作是DOS调用的一个子程序 而DOS对主过程的调用和返回都是FAR属性 过程定义允许嵌套 即在一个过程定义中可允许包含多个过程定义 例 调用程序和子程序同在一个代码段中 且有嵌套的例子 CODESEGMENT MAINPROCFAR 定义主过程 CALLPRG1 RET 主过程返回PRG1PROCNEAR CALLPRG2 RETPRG2PROCNEAR RETPRG2ENDPPRG1ENDPMAINENDPCODEENDS这个例子的过程定义相当于三层嵌套 主过程MAIN中嵌套了子过程PRG1 而子过程PRG1中又嵌套了一个子过程PRG2 它们共同属于一个代码段中 除主过程看成为DOS调用的一个子程序要用FAR属性外 其余二个子过程都为NEAR属性 例 调用程序和子程序分属于不同的代码段 CODE1SEGMENT PUBLICPRG1PRG1PROCFAR RETPRG1ENDP CODE2SEGMENTEXTRNPRG1 FAR CALLPRG1 CODE2ENDS子程序除了用过程的形式定义外 还可直接书写成如下形式 子程序名 子程序功能程序段RET 子程序返回 在屏幕上显示OK 的子程序调用形式的简单例子 CODESEGMENTASSUMECS CODEGO MOVAL O CALLDISPMOVAL K CALLDISPMOVAL MOVAH 4CHINT21HDISP MOVAH 2 单字符显示子程序形式MOVDL ALINT21HRET 子程序返回CODEENDSENDGO 调用程序和子程序间的参数传递方法调用程序在调用子程序之前 必须把该次需要在子程序中处理的数据传递给子程序 这些要处理的数据称为子程序的输入参数 或称入口参数 有时 当子程序执行后返回调用程序需要把本次调用处理的最终结果传递给调用程序 这就是子程序的输出参数 或称为出口参数 所以 把调用程序传递输入参数和子程序传递输出参数的过程称为调用程序与子程序之间的参数传递 调用程序和子程序之间的参数传递大体有三种办法 1 利用寄存器传递参数较简单的办法是在调用程序中 把输入参数存放于寄存器中 进入子程序后 就可以直接从这些寄存器中取出输入参数 子程序运行中若需要向调用程序返回数据 也可以把这些数据存于指定的寄存器中 由它们带回调用程序 此法比较简便 但受CPU寄存器数量限制 则只适合于传递参数较少的场合 应用这种方法设计子程序时 调用程序和子程序必须按事先约定在指定的寄存器中存入或取出指定参数 按处理问题的情况通常可把某个寄存器既可以用作存放输入参数的寄存器 又同时可以用作存放输出参数的寄存器 并非所有子程序都有入口参数或出口参数 也需要具体问题具体分析 例 检验一个字符是否为数字字符的子程序 要求 对给定的一组字符串 查找其中0 9的字符 如找到送显示并统计数字字符的个数 同时把原数字字符单元用空格填入 分析 为了在字符串中寻找数字字符 必须一个字符一个字符的查找 则可单独用一个子程序进行字符的判断 若为数字字符并给予显示 本例将通过寄存器方式进行程序间的参数传递 入口参数选用AL寄存器存放待检测的字符 出口参数选用AH寄存器存放检测结果的返回标志 规定AH 0 表明不是数字字符 当AH 0FFH时 表明为数字字符 数字字符的统计由调用程序中的CL寄存器实现 源程序为 DATASEGMENTSTRINGDB A123BC456F811 字符串COUNTDB DATAENDSSTAKSEGMENTSTACKDW100DUP STAKENDSCODESEGMENTASSUMECS CODE DS DATA START MOVAX DATAMOVDS AXLEABX STRING 取字符串首地址的有效地址MOVCL 0 统计数字字符个数寄存器清0LP MOVAL BX 取一个字符CMPAL 是终止标志吗 JZDONE 是 结束操作CALLFINDS 非终止符 转子程序CMPAH 0 判是否数字字符JZL1 非数字符 转L1INCCL 统计数字符MOVBYTEPTR BX 改数字字符之处为空格L1 INCBXJMPLP 检查下一个字符DONE MOVCOUNT CL 存统计结果MOVAH 4CHINT21H FINDSPROCNEAR 判断字符子程序CMPAL 0 JBL2 非数字 转L2CMPAL 9 JAL2 非数字 转L2MOVAH 2 显示数字符MOVDL ALINT21HMOVAH 0FFH 置返回标志 找到数字字符RETL2 MOVAH 0 不是数字字符L3 RETFINDSENDPCODEENDSENDSTART 例 把一个字单元中的4位8421BCD码分离成4个非压缩的BCD码 存放在以变量BUF为首地址的4个字节单元中 低位在低地址 高位在高地址 分离完成后送显示 试编制以调用程序与子程序形式的源程序 编程中约定 用BX存放待转换的4位BCD码 用SI作为存放单元的地址寄存器 源程序如下 DATASEGMENTADDRDW4567HBUFDB4DUP DATAENDSSTAKSEGMENTSTACKDW100DUP STAKENDSCODESEGMENTASSUMECS CODE DS DATAMAINPROCFAR 主程序写成主过程的形式START PUSHDSMOVAX 0PUSHAX 返回DOS的方法之一 MOVAX DATAMOVDS AXMOVSI OFFSETBUFMOVBX ADDRCALLBCDSUBLEASI BUF 3 以下为显示程序段MOVCX 4MOVAH 2LOP1 MOVDL SI ORDL 30HINT21HDECSILOOPLOP1RET 子程序名 BCDSUB 功能 将一个字的4位BCD码分解成4个非压缩BCD码 输入参数 BX中存放4位BCD码 SI作为存放结果单元地址寄存器 输出参数 分离后存放到BUF为首址的4个字节单元中 所选用寄存器 AX BX CX DX SI 示例 BX 4567H分离后 在BUF单元起有07060504 BCDSUBPROCNEARPUSHBX 保护现场PUSHCXPUSHDXMOVCX 404H CH为循环数 CL存放移动次数LOP MOVDL BL 保存数据ANDDL 0FH 取最低位BCD码存于BL中MOV SI DL 存放结果单元INCSI 修改存数地址SHRBX CLDECCHJNZLOPPOPDXPOPCX 恢复现场POPBXRETBCDSUBENDPMAINENDPCODEENDSENDSTART 2 利用堆栈传递参数参数传递的第二种方法是利用堆栈 在调用子程序之前 调用程序将子程序需要的输入参数逐个压入堆栈 在进入子程序后再从堆栈中弹出这些数据 同理输出参数也可以通过堆栈来完成 看后面例子 采用堆栈的优点是可以传递较多的参数 但要注意不可破坏断点地址以及进出栈的顺序 利用堆栈来传递参数 既可传递数据 也可以是地址 特别要注意堆栈中的断点保护与恢复 从调用程序进入子程序时 栈顶保存的内容为断点地址 子程序返回地址 例 试编制一个将字符串STR1传送到字符串STR2的调用程序与子程序 设两串无地址重叠 并将STR2串送显示 分析 这也是很简单的问题 用以体会利用堆栈传递参数的方法 为实现字符串的传送需要三个入口参数 即源串STR1的偏移首地址出入SI 目的串STR2的偏移首地址存入DI和字符串长度存入CX 在调用子程序之前 调用程序应将它们压入堆栈 进入子程序后 再经出栈指令依次取出这些参数 DATASEGMENTSTR1DB AB 源串NEQU STR1STR2DBNDUP DATAENDSSTAKSEGMENTSTACKDW100DUP STAKENDSCODESEGMENTASSUMECS CODE DS DATA ES DATAMAINPROCFARSTART PUSHDSMOVAX 0PUSHAX MOVAX DATAMOVDS AXMOVES AXLEASI STR1LEADI STR2MOVCX NPUSHCX 入口参数3进栈PUSHDI 入口参数2进栈PUSHSI 入口参数1进栈CALLSMOVBRET 子程序名 SMOVB 功能 完成字符串传送 并显示STR2 输入参数 源 目的串首址及字符串长度的SI DI CX进栈 输出参数 在附加段中存放STR2开始的目的串SMOVBPROCNEARPOPBX 取出断点地址偏移量POPSI 取出输入参数1POPDI 取出输入参数2POPCX 取出输入参数3PUSHBX 恢复断点保存 要关注断点地址CLD 增址方向REPMOVSB 重复串传送LEADX STR2 9号功能的字符串显示MOVAH 9INT21HRETSMOVBENDPMAINENDPCODEENDSENDSTART 3 利用存储单元传递参数第三种参数传递的方法是开辟一个存储区来传递参数 可以事先定义从内存的某个地址开始 按一定的次序存放输入参数和输出参数 这种方法适用于参数较多的场合 堆栈是特殊的存储区 它以 后进先出 原则存取信息 还有一种传递较多参数的方法是在内存中使用一个约定的存储区来保存和传递调用程序和子程序间的参数 调用程序在调用子程序前将所有输入参数按预先安排好的次序存入约定的存储区 进入子程序后又按约定从存储区中取出输入参数进行处理 子程序处理的输出参数也按约定的次序 具体算法 取出第一字节单元内容与第二个单元内容左移四位后相加 相或 存于BCD字单元的低字节 再取出第三字节单元内容与第四个字节单元内容左移四位后相加 相或 存于BCD字单元的高字节 DATASEGMENTBUFDB07 06 05 04BCDDW DATAENDSSTAKSEGMENTSTACKDB100DUP CODESEGMENTASSUMECS CODE DS DATASTART MOVAX DATAMOVDS AX CALLMERGE MOVAH 4CHINT21H MERGEPROCNEARPUSHAX 保护现场PUSHBXPUSHCXPUSHDXLEASI BUF 取首址MOVAL SI 取第一字节MOVBL SI 1 取第二字节MOVCL 4 左移四位SHLBL CLADDAL BL 合并两位BCD码MOVAH SI 2 取第三字节MOVBH SI 3 取第四字节SHLBH CL 左移四位ADDAH BHMOVBCD AX 存结果POPDXPOPCXPOPBXPOPAXRETMERGEENDPCODEENDSENDSTART 注意 前面所介绍的三种传递参数的方法 并不是固定不变的 即它们是可以综合使用的 要按照实现的需要和具体情况的不同 可以使用其中一种方式 也可以同时使用几种混合的方式 有的时候还可能并不需要参数的传递 总之 调用程序和子程序之间的参数传递 的确十分重要 参数不宜使用太多 参数选择的适当 可以简化程序设计 参数确定之后 就是如何进行传递的问题 无论采用哪一种传递方式 都应该保证正确无误的传递 这是调用程序和子程序的协调关系 这也是在子程序设计中需要认真解决的问题 11 3 3子程序的嵌套一个程序可以调用一个或多个子程序 而一个子程序也可以调用另一个子程序 这种情况就称为子程序的嵌套 即在子程序中可以镶嵌着另一个子程序 子程序可以多次嵌套 它的嵌套次数只受堆栈容量大小的约束 不受其它因素的影响 其嵌套层数称为嵌套深度 图11 4表示了嵌套深度为2的子程序调用情况 主程序子程序A子程序BSUBASUBB CALLSUBACALLSUBB RETRET图11 4子程序的嵌套嵌套子程序的设计并没有什么特殊的要求 除了子程序的调用和返回应正确使用CALL和RET指令外 要注意各子程序之间所使用的寄存器合理保护和恢复 以避免各层子程序之间发生因寄存器冲突而出现错误的情况 如果程序中使用堆栈来传递参数 则对堆栈的操作要格外小心 以免因堆栈使用中的问题 可能造成程序不能正确返回而出现错误 如果是段间嵌套调用 则应该解决好段间的连接关系 例11 13 将变量A地址开始的20个字节单元中的内容按十六进制数形式转换为相应的40个ASCII码 存于B地址开始的40个字节单元中 按 低位在低地址 高位在高地址 的原则存放 编程要求 每个字节的高 低四位分离 然后需要把每个十六进制数转换为相应的ASCII码 为了理解子程序嵌套的结构 我们把本例的简单问题按嵌套深度为2的子程序来编写 也就是使用二级子程序来实现上述任务 用第一级子程序SUB1完成字节单元中二个十六进制数分离 再调第二级子程序SUB2完成十六进制数到ASCII码的转换任务 主程序只负责调用SUB1子程序和控制循环等操作 在完成所有单元数的转换后 返回DOS系统 源程序清单如下 DATASEGMENTADB37H 0FCH 9AH 共20个字节BDB40DUP DATAENDSSTAKSEGMENTSTACKDW20DUP STAKENDSCODESEGMENTASSUMECS CODE DS DATASTART MOVAX DATAMOVDX AXLEASI ALEADI B MOVCX 20LP MOVAL SI 取一字节数CALLSUB1INCSIINCDILOOPLPMOVAH 4CHINT21HSUB1PROCNEARMOVBL AL 存待转换数ANDAL 0FH 取低4位CALLSUB2 调转换为ASCII码子程序MOV DI ALINCDIMOVAL BL 子程序SUB2的入口参数在AL中MOVCL 4SHRAL CLCALLSUB2MOV DI ALRETSUB1ENDP 子程序2 SUB2 入口参数 AL中低4位为1个16进制数 出口参数 AL中转换后的ASCII码 SUB2PROCNEARCMPAL 9JBEL1ADDAL 7 是字母A F预加7L1 ADDAL 30HRETSUB2ENDPCODEENDSENDSTART11 4子程序设计举例子程序的设计 是程序设计中被广泛使用的一种方法 通过前面内容的学习可以知道 它的使用方式较多 运用十分灵活 涉及面也比较广 需要掌握好基本的子程序设计方法 以下从应用的角度 举几个较为实用的子程序供读者参考 例11 14 编制一个简单的加密和解密程序 其功能为 1 从键盘输入数字0 9 经加密后存入内存单元 从键盘输入数字由子程序KEYIN完成 2 将加密过的数据进行解密 并将解密后的数字在屏幕上显示出来 其显示可由子程序OUTDSP完成 对数字0 9加密和解密的数据 其约定关系是 原数字 0123456789 未加密的数字密码数字 6291378054 原数字对应的密码解密数字 7314980562 分析 首先是对键盘上输入的0 9的数字进行加密 说明其加密操作 其后解密送显示 仅是说明解密的道理 不然一个程序既加密又解密就没有意义了 应该注意到 从键盘上输入的数字是ASCII码 加密时要屏蔽掉高四位 而BCD码送显示时又要转换成ASCII码 完成0 9数字输入要经01号功能的DOS调用 显示输出的BCD码经02号功能的DOS调用来实现 本程序只说明一位数字的加密问题 源程序如下 DSEGSEGMENTMIMABDB 6291378054 可任意拟定JMIMABDB 7314980562 根据MIMA拟定MIMADB 存一位密码DSEGENDSSSEGSEGMENTSTACKDW50HDUP SSEGENDSCSEGSEGMENTASSUMECS CODE DS DSEG MAINPROCFAR 按主过程定义START PUSHDSSUBAX AXPUSHAXMOVAX DSEGMOVDS AXCALLKEYINMOVBX OFFSETMIMABXLATANDAL 0FHMOVMIMA AL 存密码MOVBX OFFSETJMIMABXLATCALLOUTPUTRET 子程序名 KEYIN 功能 人键盘输入一个0 9数字 并转换为BCD码 入口参数 无 出口参数 AL 占用寄存器 AX KEYINPROCNEARMOVAH 1INT21HANDAL 0FHRETKEYINENDP 子程序名 OUTDSP 功能 将加密后的数据在屏幕上显示出来 入口参数 AL 出口参数 无 占用寄存器 AX DX OUTDSPPROCNEARORAL 30HMOVDL ALMOVAH 2INT21HRETOUTDSPENDPMAINENDPCSEGENDSENDSTART本程序是一个比较简单的问题 编写成段内子程序调用的方式 其用意仍然是通过简单的问题去体会子程序的编程方法 例11 15 完成二个无符号字数据的乘法运算 使用两个独立模块进行设计 本例可以划分为二个独立的模块 主模块与子模块 由子模块完成乘积运算 过程名是通过伪指令EXTRN与PUBLIC完成两个独立模块之间的交互连接 源程序为 NAMEMODULE1EXTRNSUBMUL FARDATASEGMENTDAT1DW030AHDAT2DW2218HRESLDW2DUP DATAENDSSTAKSEGMENTSTACKDW100DUP STAKENDS CODESEGMENTASSUMECS CODE DS DATABEGIN MOVAX DATAMOVDS AXMOVAX DAT1MOVBX DAT2CALLSUBMULMOVRESL AXMOVRESL 2 DXMOVAX 4C00HINT21HCODEENDSENDSBEGIN NAMEMODULE2CODESEGMENTSUBMULPROCFARASSUMECS CODEPUBLICSUBMULMULBX DX AX AX BXRETSUBMULENDPCODEENDSEND 例1
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030中国基建行业发展规划与未来前景预测报告
- DB50-T 1201-2021 区域界线标识标志设置规范
- 2025-2030中国四元锂电池正极材料(NCMA)行业发展态势与投资规划研究报告
- 老年人消化不良共识总结2026
- 护理操作规范指南
- 国家安全管理标准培训
- 七年级数学教师教学工作总结10篇
- 古代中国民间故事集成
- 中医学专业职业规划-1
- 销售五年成长蓝图
- 2026年黑龙江省《保密知识竞赛必刷100题》考试题库附参考答案详解(精练)
- 西南名校联盟2026届3+3+3高三4月联考数学试卷+答案
- 成都环境投资集团有限公司下属成都市兴蓉环境股份有限公司2026年春季校园招聘(47人)笔试历年参考题库附带答案详解
- GB 20055-2006开放式炼胶机炼塑机安全要求
- 物探-地震勘探理论基础
- 蒋丁新版饭店管理第七章-饭店营销管理
- 火力发电厂生产技术管理导则
- 英语四六级考前15天提高听力成绩必备技巧
- RG-S8600E云架构网络核心交换机产品介绍(V1.3)
- 【PPT】量子计算研究进展
- GJB9001B-2009《质量管理体系要求》
评论
0/150
提交评论