资讯动态

河北专升本汇编第四章:伪指令与程序设计备考指南

发布时间:2026/10/22 14:48:14 来源:尧图企业网站定制
1. 为什么第四章是专升本汇编的分水岭1.1 从“能看懂”到“能写出来”的跨越河北专升本计算机专业的微机原理与接口技术很多同学的复习轨迹都差不多前三章学完感觉自己还行数制转换会了8086的寄存器结构背了寻址方式也能说出个一二三。但一翻到第四章看到伪指令、程序结构、各种汇编语句突然就懵了。这不是个别现象而是绝大多数考生的共同瓶颈。原因很简单前三章考的是“认”第四章考的是“写”。认一个东西和写一个东西难度差了一个量级。就像你认识汉字不等于能写出一篇作文你能看懂别人的代码不等于你能自己从零写一个完整的汇编程序。第四章恰恰就是要求你从“读者”变成“作者”。河北专升本的考纲里第四章的分值占比一直不低。伪指令部分通常出选择题和填空题程序设计的部分则经常出阅读分析题和编程题。阅读分析题给你一段代码让你写结果编程题让你用汇编实现一个简单功能。这两类题目的得分率在所有题型里是最低的不是因为知识点有多难而是因为大部分考生没有真正动手写过完整的汇编程序。1.2 这一章到底要学什么先把第四章的内容框架理清楚。这一章主要包含两大块汇编伪指令和汇编程序设计。伪指令这块核心要掌握的是数据定义伪指令DB、DW、DD、符号定义伪指令EQU、、段定义伪指令SEGMENT/ENDS、ASSUME、过程定义伪指令PROC/ENDP、以及定位伪指令ORG和结束伪指令END。这些伪指令本身不产生机器码它们是给汇编器看的“指令”告诉汇编器怎么组织代码和数据。程序设计这块核心是三种基本结构顺序结构、分支结构、循环结构。分支用CMP加条件跳转指令实现循环用LOOP指令或者条件跳转配合计数器实现。再往上就是子程序设计和常用的DOS中断调用比如INT 21H的01H、02H、09H、0AH、4CH功能号。听起来内容不多但真正要写代码的时候你会发现坑一个接一个。伪指令的格式记错了汇编器直接报错跳转指令选错了程序逻辑完全跑偏循环的计数器忘了设置程序死循环。这些问题在考试里就是丢分点在实际操作中就是调试的噩梦。1.3 备考策略的核心逻辑针对河北专升本的考试特点第四章的备考策略应该是“先框架后细节先手写后机调”。所谓“先框架后细节”是指先把一个完整汇编程序的结构骨架记住。一个标准的汇编程序长什么样无非就是数据段、堆栈段、代码段三个段用SEGMENT和ENDS包起来用ASSUME告诉汇编器段和段寄存器的对应关系代码段里用PROC和ENDP包住主过程最后用END结束。这个骨架你背下来考试的时候先把框架搭好再往里填具体逻辑心里就不慌。所谓“先手写后机调”是指不要一上来就打开电脑写代码调试。考试是笔试你需要在纸上写出正确的代码。所以平时练习就要用纸笔写写完再对照答案检查。手写能暴露很多问题比如标号忘了写、冒号漏了、操作数顺序搞反了这些问题在IDE里可能被自动补全或者语法检查帮你兜住但考试的时候没人帮你。我见过太多同学平时在电脑上敲代码敲得飞起一到考试手写就各种低级错误。所以这一章的学习纸笔练习的时间不能少于上机练习的时间。2. 伪指令的核心细节与避坑指南2.1 数据定义伪指令DB、DW、DD到底怎么选数据定义伪指令是第四章最基础也是考得最细的知识点。DB定义字节DW定义字DD定义双字。看起来简单但考试就爱在这些细节上做文章。先看一个典型的考题形式DATA SEGMENT VAR1 DB 10H, 20H, 30H VAR2 DW 1234H, 5678H VAR3 DD 12345678H DATA ENDS问VAR1、VAR2、VAR3各占多少个字节VAR1占3个字节VAR2占4个字节VAR3占4个字节。这个不难但考试会变着花样问。比如问VAR21这个地址里存的是什么你需要知道8086是小端模式低字节存在低地址高字节存在高地址。所以VAR2的第一个字1234H在内存里是34H存在低地址12H存在高地址。VAR21指向的是12H。再比如用DUP定义重复数据ARRAY DB 10 DUP(0)这表示定义10个字节每个字节的值都是0。DUP前面的数字表示重复次数括号里是重复的内容。考试会问这个ARRAY占多少字节答案是10个字节。如果写成DB 5 DUP(1, 2)那就是重复5次“1, 2”这个序列总共占10个字节内容是1, 2, 1, 2, 1, 2, 1, 2, 1, 2。这里有一个容易踩的坑DUP可以嵌套。比如DB 2 DUP(3 DUP(1))这表示外层重复2次每次的内容是3个1所以总共6个字节全是1。嵌套DUP在考试里出现过很多同学第一次见会算错。还有一个细节用DB定义字符串的时候字符串要用单引号括起来。比如DB HELLO这在内存里占5个字节分别是H、E、L、L、O的ASCII码。注意不是6个字节没有自动加结束符。如果你需要字符串以$结尾方便用INT 21H的09H功能输出要写成DB HELLO$。注意DB、DW、DD后面跟的数据不能超过对应类型的范围。DB的范围是0到255无符号或-128到127有符号DW的范围是0到65535或-32768到32767。超范围汇编器会报错考试的时候如果写了超范围的数据直接扣分。2.2 符号定义伪指令EQU和的区别EQU和都是用来定义符号常量的但有一个关键区别EQU定义的符号不能重复定义定义的符号可以重新定义。COUNT EQU 10 COUNT EQU 20 ; 这行会报错COUNT已经定义过了 NUM 10 NUM 20 ; 这行没问题NUM被重新定义为20考试里经常出这样的题给出一段代码问哪些行会报错。你只要记住EQU是“一次性的”是“可变的”就能判断出来。还有一个细节EQU定义的符号不占内存空间它只是一个编译时的替换。比如你写COUNT EQU 10然后在代码里用MOV CX, COUNT汇编器会把COUNT替换成10实际生成的机器码就是MOV CX, 10。所以EQU定义的符号不能和已有的标号或变量名重名否则汇编器会报“符号重复定义”的错误。在实际写程序的时候EQU通常用来定义一些常量比如缓冲区大小、端口地址等。通常用在需要动态改变值的地方比如循环计数器的初值。不过说实话在专升本考试的程序设计题里用EQU就足够了用得比较少。2.3 段定义伪指令ASSUME不是可写可不写的段定义伪指令是汇编程序框架的核心。一个标准的段定义长这样DATA SEGMENT ; 数据定义 DATA ENDS STACK SEGMENT STACK ; 堆栈定义 STACK ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START: ; 代码 CODE ENDS END START这里有几个关键点第一ASSUME伪指令的作用是告诉汇编器某个段寄存器对应哪个段。比如ASSUME CS:CODE告诉汇编器CS寄存器指向CODE段。ASSUME本身不产生任何机器码它只是给汇编器提供信息让汇编器在生成代码的时候知道怎么处理段超越前缀和变量寻址。第二ASSUME只是“告诉”汇编器并没有真正把段地址装入段寄存器。真正装入段地址需要在代码里用MOV指令完成。比如MOV AX, DATA MOV DS, AX这两行代码把DATA段的段地址装入DS寄存器。很多同学会问为什么不能直接MOV DS, DATA因为8086的指令集不允许直接把立即数装入段寄存器必须通过通用寄存器中转。第三堆栈段的定义有一个特殊写法STACK SEGMENT STACK。第二个STACK是段属性告诉汇编器这个段是堆栈段。有了这个属性汇编器会自动设置SS和SP的值你不需要在代码里手动初始化堆栈。如果写成STACK SEGMENT没有第二个STACK那就需要自己初始化SS和SP。考试里经常考的一个点是ASSUME伪指令的作用是什么标准答案是告诉汇编器段和段寄存器的对应关系但不实际装入段地址。这个答案要背准确选择题和填空题都可能考。2.4 过程定义伪指令PROC和ENDP的配对使用过程定义伪指令用来定义一个子程序。格式是SUBROUTINE PROC ; 子程序代码 RET SUBROUTINE ENDPPROC和ENDP必须成对出现而且标号名必须一致。子程序内部通常以RET指令结束返回到调用处。调用子程序用CALL指令。这里有一个容易忽略的细节PROC后面可以跟属性比如PROC FAR表示远过程PROC NEAR表示近过程。在专升本考试里通常不区分FAR和NEAR默认用NEAR就行。但如果题目明确要求用FAR你要知道FAR过程返回时需要用RETF指令。还有一个坑子程序里如果修改了主程序用到的寄存器要在子程序开头用PUSH保存在RET之前用POP恢复。这个操作叫“保护现场”。考试里的编程题如果要求写子程序不保护现场可能会扣分因为主程序可能依赖某些寄存器的值。2.5 定位伪指令和结束伪指令ORG和ENDORG用来指定后续代码或数据的起始偏移地址。比如CODE SEGMENT ORG 100H START: ; 代码从偏移地址100H开始 CODE ENDSORG在考试里出现频率不高但要知道它的作用。如果题目里出现了ORG你要能说出它指定了后续内容的起始偏移地址。END伪指令标记整个源程序的结束格式是END 标号标号通常是程序入口点的标号。比如END START表示程序从START标号处开始执行。END后面的标号可以省略但考试里建议写上因为这是标准写法。提示一个源程序只能有一个END而且必须放在所有段的最后。如果END后面还有代码汇编器会忽略。3. 汇编程序设计的三种结构与实操写法3.1 顺序结构最简单的往往最容易丢分顺序结构就是代码从上到下依次执行没有跳转。看起来简单但考试里顺序结构的题目往往暗藏杀机。看一个典型的顺序结构题目MOV AL, 05H ADD AL, 03H MOV BL, AL SUB BL, 02H问执行完后AL和BL的值分别是多少AL是08HBL是06H。这个不难但考试会加入各种细节。比如把ADD换成ADC把SUB换成SBB这时候就要考虑进位标志CF的影响。顺序结构里最常考的是算术运算指令对标志位的影响。ADD、SUB、INC、DEC、MUL、DIV这些指令执行后CF、ZF、SF、OF标志位分别是什么值这是必考内容。我整理了一个速查表指令CFZFSFOFADD有进位则1结果为0则1结果最高位为1则1溢出则1SUB有借位则1结果为0则1结果最高位为1则1溢出则1INC不影响结果为0则1结果最高位为1则1溢出则1DEC不影响结果为0则1结果最高位为1则1溢出则1MUL结果高半部分不为0则1不确定不确定结果高半部分不为0则1DIV不确定不确定不确定除数为0或商溢出则1这个表要背熟。考试里经常出“执行完某条指令后CF和ZF的值是什么”这样的题你查表就能答出来。顺序结构还有一个常考点是交换指令XCHG。比如XCHG AX, BX把AX和BX的值互换。注意XCHG不能交换两个内存单元的值也不能交换段寄存器的值。考试里如果出现XCHG [SI], [DI]这样的写法那是错误的因为两个操作数不能同时是内存单元。3.2 分支结构CMP和条件跳转的配合分支结构是考试的重点也是编程题最常考的结构。分支结构的核心是CMP指令加条件跳转指令。CMP指令做减法但不保存结果只影响标志位。比如CMP AL, 10相当于做AL-10根据结果设置ZF、CF、SF、OF等标志位。然后根据这些标志位用条件跳转指令决定是否跳转。条件跳转指令分三类无符号数比较跳转、有符号数比较跳转、以及根据单个标志位跳转。无符号数比较跳转指令含义跳转条件JA大于则跳转CF0且ZF0JAE大于等于则跳转CF0JB小于则跳转CF1JBE小于等于则跳转CF1或ZF1有符号数比较跳转指令含义跳转条件JG大于则跳转ZF0且SFOFJGE大于等于则跳转SFOFJL小于则跳转SF≠OFJLE小于等于则跳转ZF1或SF≠OF这两组指令的区别在于无符号数比较用JA/JB系列有符号数比较用JG/JL系列。考试里经常出这样的题给两个数问用哪个跳转指令。关键看这两个数是有符号数还是无符号数。如果是无符号数比如地址、ASCII码用JA/JB如果是有符号数比如温度、坐标用JG/JL。我见过很多同学在这里丢分就是因为没看清题目说的是有符号还是无符号。有一个简单的判断方法如果题目里的数出现了负数那肯定是有符号数如果都是正数要看题目有没有明确说“无符号数”。如果没说默认按有符号数处理。分支结构的典型编程题是从键盘输入一个字符判断它是不是大写字母如果是则输出“YES”否则输出“NO”。这个题目的代码框架是MOV AH, 01H INT 21H ; 输入一个字符到AL CMP AL, A JB NOT_UPPER ; 小于A不是大写字母 CMP AL, Z JA NOT_UPPER ; 大于Z不是大写字母 ; 是大写字母 MOV DL, Y MOV AH, 02H INT 21H JMP DONE NOT_UPPER: MOV DL, N MOV AH, 02H INT 21H DONE:这个代码里有两个CMP和两个条件跳转逻辑是“与”的关系既要大于等于A又要小于等于Z。考试里经常考这种多条件判断你要能正确使用多个CMP和跳转指令。注意条件跳转指令的跳转范围是-128到127字节。如果跳转目标太远汇编器会报“跳转超出范围”的错误。考试里一般不会出这种题但你要知道有这个限制。如果确实需要远距离跳转可以用JMP指令中转。3.3 循环结构LOOP指令和计数器循环结构的核心是LOOP指令。LOOP指令的格式是LOOP 标号执行时先把CX减1然后判断CX是否为零如果不为零则跳转到标号处。使用LOOP指令的关键是正确设置CX的值。比如要循环10次就在循环开始前MOV CX, 10。注意LOOP是先减CX再判断所以如果CX初值为0执行LOOP会变成FFFFH然后循环65535次。这是一个常见的坑。看一个典型的循环结构题目求1到100的累加和。MOV AX, 0 MOV CX, 100 MOV BX, 1 SUM_LOOP: ADD AX, BX INC BX LOOP SUM_LOOP执行完后AX里就是1到100的和。这个代码里CX从100递减到0循环100次。每次循环把BX加到AX然后BX加1。循环结构里还有一个常考的点是循环嵌套。比如打印一个九九乘法表就需要两层循环。外层循环控制行内层循环控制列。嵌套循环的坑在于内层循环会修改CX的值所以外层循环的CX必须在内层循环开始前保存起来。通常的做法是用堆栈保存MOV CX, 9 ; 外层循环9次 OUTER: PUSH CX ; 保存外层CX MOV CX, 9 ; 内层循环9次 INNER: ; 内层循环体 LOOP INNER POP CX ; 恢复外层CX LOOP OUTER这个PUSH和POP的操作是嵌套循环的关键。很多同学写嵌套循环的时候忘了保存CX结果外层循环只执行一次就结束了。除了LOOP指令循环还可以用条件跳转实现。比如MOV CX, 10 LOOP_START: ; 循环体 DEC CX JNZ LOOP_START这种写法和LOOP指令的效果一样但更灵活因为可以在循环体里修改CX的值。考试里两种写法都可能出现你要都能看懂。3.4 子程序设计CALL和RET的配合子程序设计是第四章的进阶内容。考试里的编程题如果分值较高通常会要求用子程序实现。子程序的定义用PROC和ENDP调用用CALL返回用RET。子程序的设计要点有三个第一参数传递。子程序的参数可以通过寄存器传递也可以通过堆栈传递。考试里通常用寄存器传递比如把要处理的数放在AL里子程序处理完把结果放在AL里返回。第二保护现场。子程序里如果要用到主程序也在用的寄存器要在子程序开头PUSH保存在RET之前POP恢复。通常需要保护的寄存器是BX、CX、DX、SI、DI等。AX通常用来返回结果不需要保护。第三子程序的独立性。子程序应该是一个独立的功能模块不依赖主程序的特定状态。比如一个求绝对值的子程序输入放在AL输出放在AL不管主程序的其他寄存器是什么值子程序都能正确工作。看一个典型的子程序题目写一个子程序判断AL中的数是不是偶数是则把ZF置1否则把ZF置0。CHECK_EVEN PROC TEST AL, 01H ; 测试最低位 RET CHECK_EVEN ENDP这个子程序用TEST指令测试AL的最低位。如果最低位是0说明是偶数ZF被置1如果最低位是1说明是奇数ZF被置0。调用的时候MOV AL, 08H CALL CHECK_EVEN JZ IS_EVEN ; 是奇数 JMP DONE IS_EVEN: ; 是偶数 DONE:这个子程序很短但体现了子程序设计的核心思想输入通过AL传递输出通过标志位传递子程序内部不修改其他寄存器。考试里的子程序题目通常比这个复杂比如要求写一个子程序实现两个数的乘法不能用MUL指令或者实现字符串的复制。但不管多复杂设计思路是一样的明确输入输出保护现场用RET返回。4. 常见问题与排查技巧实录4.1 汇编器报错速查表手写汇编代码的时候最怕的就是汇编器报错。考试的时候虽然没有汇编器帮你检查但你要有“人肉汇编器”的能力写完代码自己检查一遍。下面是我整理的一份常见错误速查表错误现象可能原因解决方法符号重复定义EQU定义的符号重名或标号重名检查所有符号名确保唯一操作数类型不匹配DB定义的变量用MOV AX直接访问用MOV AL访问字节变量或用MOV AX配合类型转换跳转超出范围条件跳转目标太远用JMP中转或改用LOOP段寄存器直接赋立即数MOV DS, 1000H通过通用寄存器中转缺少END源程序没有END伪指令在最后一行加END 标号PROC和ENDP不配对过程定义缺少ENDP检查每个PROC都有对应的ENDP堆栈溢出PUSH次数多于POP次数检查PUSH和POP是否配对死循环LOOP指令的CX初值为0确保CX初值不为0这张表里的每一条都是我在实际写代码和辅导学生时反复遇到的。尤其是“操作数类型不匹配”这一条考试里经常出。比如DATA SEGMENT VAR DB 10H DATA ENDS CODE SEGMENT MOV AX, VAR ; 这行会报错 CODE ENDSVAR是用DB定义的字节变量MOV AX是字操作类型不匹配。正确的写法是MOV AL, VAR或者MOV AH, 0加MOV AL, VAR。考试里如果出了这样的代码让你找错你要能一眼看出来。4.2 程序阅读题的解题套路河北专升本第四章的考试题型里程序阅读题是必考的。题目给出一段汇编代码问你执行完后某个寄存器或内存单元的值是什么。这类题目的解题套路是第一步画内存图和寄存器图。把题目里涉及的段、变量、寄存器都画出来标上初始值。第二步逐行模拟执行。从第一条指令开始一条一条往下走每执行一条就更新寄存器和内存的值。遇到跳转指令根据标志位判断是否跳转。第三步检查结果。执行到最后一条指令后检查题目问的寄存器或内存单元的值。这个套路听起来笨但最可靠。我见过很多同学试图“一眼看出”结果结果不是漏了某条指令就是搞错了标志位。老老实实逐行模拟虽然慢一点但正确率高。举个例子MOV AX, 1234H MOV BX, 5678H ADD AX, BX问执行完后AX的值是多少逐行模拟AX1234HBX5678HADD AX, BX后AX1234H5678H68ACH。注意进位1234H5678H68ACH没有超过FFFFH所以CF0。如果题目问CF的值答案是0。再复杂一点的MOV AL, 0FFH ADD AL, 01HAL0FFH加01H后AL00HCF1ZF1。这个题目考的是溢出和进位的区别。0FFH01H100H但AL只能存8位所以AL00H进位到CF。注意这不是有符号溢出OF0因为0FFH作为有符号数是-1-110没有溢出。程序阅读题的关键是分清CF和OF的区别。CF是无符号进位OF是有符号溢出。考试里经常出这种题来区分这两个标志位。4.3 编程题的评分标准和拿分技巧编程题是第四章分值最高的题型也是最能拉开差距的题型。根据我对河北专升本评分标准的了解编程题的评分通常分三部分程序框架30%、核心逻辑50%、细节处理20%。程序框架就是段定义、ASSUME、PROC/ENDP、END这些。这部分是送分题只要你背了标准框架就能拿到。但很多同学因为紧张或者时间不够框架写得不完整比如忘了写ASSUME或者忘了END直接丢掉30%的分数。核心逻辑就是题目要求的功能实现。比如题目要求“从键盘输入10个字符统计其中大写字母的个数”核心逻辑就是循环输入、判断大写字母、计数。这部分要写清楚每一步都要有对应的指令。细节处理包括保护现场、注释、标号命名等。保护现场前面说过了注释在考试里不是必须的但写了会给阅卷老师好印象。标号命名要规范不要用A、B、C这种无意义的标号用LOOP_START、CHECK_UPPER这种有意义的标号。拿分技巧方面我总结了几条第一先写框架再填逻辑。拿到题目先花两分钟把框架搭好再往里面填具体代码。这样即使后面逻辑没写完框架分也能拿到。第二不确定的指令用注释说明。比如你不确定某个地方该用JA还是JG可以写CMP AL, A然后注释; 判断是否大于等于A然后写JB NOT_UPPER。即使跳转指令选错了阅卷老师看到你的注释可能会给部分分数。第三代码要能“跑通”。考试的时候没有汇编器但你要在脑子里模拟执行一遍。如果发现逻辑不通赶紧改。宁可代码简单一点也不要写一个逻辑混乱的复杂代码。第四留时间检查。编程题写完后至少留5分钟检查。检查的内容包括框架是否完整、标号是否配对、跳转目标是否正确、CX是否设置、PUSH和POP是否配对。4.4 几个我踩过的坑第一个坑LOOP指令和CX的关系。我刚开始学的时候以为LOOP是“先判断再减”实际上是“先减再判断”。所以如果CX初值为1执行LOOP后CX变成0循环结束。如果CX初值为0执行LOOP后CX变成FFFFH循环65535次。这个坑我在考试里踩过题目问循环执行多少次我按“先判断”算的结果错了。第二个坑ASSUME伪指令的位置。ASSUME通常放在代码段的开头但有些同学把它放在数据段里或者放在CODE SEGMENT之前。虽然汇编器可能不报错但考试里如果问“ASSUME应该放在哪里”标准答案是“代码段内START标号之前”。第三个坑字符串的输出。用INT 21H的09H功能输出字符串时字符串必须以$结尾。我刚开始学的时候忘了加$结果程序输出了一堆乱码。考试里如果考字符串输出一定要记得在字符串末尾加$。第四个坑堆栈的初始化。如果堆栈段定义的时候没有加STACK属性就需要在代码里手动初始化SS和SP。我见过有同学忘了初始化程序运行的时候堆栈指针指向未知区域一PUSH就出错。考试里如果考堆栈相关的题目要检查SS和SP是否被正确初始化。第五个坑有符号数和无符号数的跳转指令混用。这个坑最隐蔽因为代码能跑通但逻辑是错的。比如比较两个数的大小如果是有符号数用JA/JB可能得到错误的结果。我建议在写比较跳转的时候先问自己一句这两个数是有符号还是无符号然后再选指令。5. 从零手写一个完整汇编程序的实操记录5.1 题目要求和整体思路为了把前面讲的所有知识点串起来我带你从零手写一个完整的汇编程序。题目是从键盘输入一串字符以回车结束统计其中大写字母、小写字母和数字的个数并在屏幕上输出这三个统计结果。这个题目涵盖了数据定义、段定义、输入输出、循环、分支、子程序等几乎所有第四章的知识点。如果你能独立写出这个程序第四章的编程题基本就没问题了。整体思路是这样的第一定义数据段包括输入缓冲区、三个计数器、以及输出用的提示信息。第二定义代码段主程序流程是初始化DS调用输入子程序读取字符串调用统计子程序统计各类字符个数调用输出子程序显示结果最后退出程序。第三输入子程序用INT 21H的0AH功能读取字符串统计子程序遍历缓冲区用CMP和条件跳转判断字符类型输出子程序用INT 21H的02H功能逐个输出字符。5.2 数据段和堆栈段的定义先写数据段DATA SEGMENT BUFFER DB 100 ; 缓冲区大小 DB 0 ; 实际输入的字符数 DB 100 DUP(0) ; 输入缓冲区 UPPER_CNT DB 0 ; 大写字母计数 LOWER_CNT DB 0 ; 小写字母计数 DIGIT_CNT DB 0 ; 数字计数 MSG1 DB UPPER: $ MSG2 DB 0DH, 0AH, LOWER: $ MSG3 DB 0DH, 0AH, DIGIT: $ DATA ENDS这里有几个细节要注意BUFFER的定义用了三行。第一行定义缓冲区大小第二行定义实际输入字符数初始为0第三行定义100字节的输入缓冲区。这是INT 21H的0AH功能要求的格式第一个字节是缓冲区最大容量第二个字节是实际输入的字符数由系统填入后面是输入的字符内容。MSG1、MSG2、MSG3是输出提示信息。MSG2和MSG3开头的0DH, 0AH是回车换行让输出更整齐。每个字符串都以$结尾这是09H功能的要求。堆栈段STACK SEGMENT STACK DB 100 DUP(0) STACK ENDS堆栈段定义了100字节的堆栈空间。因为加了STACK属性汇编器会自动设置SS和SP不需要在代码里手动初始化。5.3 代码段框架和主程序代码段的框架CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START: MOV AX, DATA MOV DS, AX CALL INPUT_STR CALL COUNT_CHARS CALL OUTPUT_RESULT MOV AH, 4CH INT 21H主程序只有四步初始化DS调用输入子程序调用统计子程序调用输出子程序最后用4CH功能退出。这个结构非常清晰考试的时候按这个结构写框架分就拿到了。5.4 输入子程序的实现输入子程序INPUT_STR PROC MOV DX, OFFSET BUFFER MOV AH, 0AH INT 21H RET INPUT_STR ENDP这个子程序只有三行。MOV DX, OFFSET BUFFER把缓冲区的偏移地址装入DX然后调用0AH功能。0AH功能会自动读取用户输入的字符直到按下回车然后把字符存入缓冲区并在BUFFER1处填入实际输入的字符数。注意OFFSET操作符它返回变量的偏移地址。考试里如果考到取变量地址要用OFFSET。5.5 统计子程序的实现统计子程序是核心COUNT_CHARS PROC MOV CL, BUFFER1 ; 实际输入的字符数 MOV CH, 0 MOV SI, OFFSET BUFFER2 ; 输入内容的起始地址 MOV UPPER_CNT, 0 MOV LOWER_CNT, 0 MOV DIGIT_CNT, 0 COUNT_LOOP: CMP CX, 0 JE COUNT_DONE MOV AL, [SI] CMP AL, A JB CHECK_LOWER CMP AL, Z JA CHECK_LOWER INC UPPER_CNT JMP NEXT_CHAR CHECK_LOWER: CMP AL, a JB CHECK_DIGIT CMP AL, z JA CHECK_DIGIT INC LOWER_CNT JMP NEXT_CHAR CHECK_DIGIT: CMP AL, 0 JB NEXT_CHAR CMP AL, 9 JA NEXT_CHAR INC DIGIT_CNT NEXT_CHAR: INC SI DEC CX JMP COUNT_LOOP COUNT_DONE: RET COUNT_CHARS ENDP这个子程序有几个关键点第一用BUFFER1获取实际输入的字符数。BUFFER1是缓冲区第二个字节系统在输入完成后会自动填入实际字符数。第二用SI作为指针遍历输入内容。输入内容从BUFFER2开始所以SI初始化为OFFSET BUFFER2。第三用CMP和条件跳转判断字符类型。先判断是否为大写字母A到Z再判断是否为小写字母a到z最后判断是否为数字0到9。每个判断都用两个CMP加两个条件跳转实现。第四用JMP NEXT_CHAR跳过后续判断。比如如果已经确定是大写字母就不需要再判断小写和数字了直接跳到NEXT_CHAR处理下一个字符。第五循环用CMP CX, 0加JE实现而不是用LOOP指令。因为LOOP指令只能减CX而这里CX已经被用来存字符数了用LOOP会破坏CX的值。这是一个常见的坑LOOP指令和CX的其他用途冲突时要改用条件跳转实现循环。5.6 输出子程序的实现输出子程序OUTPUT_RESULT PROC MOV DX, OFFSET MSG1 MOV AH, 09H INT 21H MOV AL, UPPER_CNT CALL PRINT_NUM MOV DX, OFFSET MSG2 MOV AH, 09H INT 21H MOV AL, LOWER_CNT CALL PRINT_NUM MOV DX, OFFSET MSG3 MOV AH, 09H INT 21H MOV AL, DIGIT_CNT CALL PRINT_NUM RET OUTPUT_RESULT ENDP PRINT_NUM PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV AH, 0 MOV BL, 10 DIV BL ; AL十位数, AH个位数 MOV CL, AH ; 保存个位数 MOV DL, AL ADD DL, 0 MOV AH, 02H INT 21H ; 输出十位数 MOV DL, CL ADD DL, 0 MOV AH, 02H INT 21H ; 输出个位数 POP DX POP CX POP BX POP AX RET PRINT_NUM ENDP输出子程序分两部分先用09H功能输出提示信息然后调用PRINT_NUM子程序输出数字。PRINT_NUM子程序把AL中的数0到99以十进制形式输出。核心逻辑是用DIV指令除以10商是十位数余数是个位数。然后分别把十位数和个位数加上0转换成ASCII码用02H功能输出。注意PRINT_NUM子程序开头有四个PUSH结尾有四个POP。这是保护现场因为子程序里用到了AX、BX、CX、DX四个寄存器如果不保护主程序里这些寄存器的值会被破坏。5.7 完整代码和测试结果把上面的代码拼起来就是完整的程序DATA SEGMENT BUFFER DB 100 DB 0 DB 100 DUP(0) UPPER_CNT DB 0 LOWER_CNT DB 0 DIGIT_CNT DB 0 MSG1 DB UPPER: $ MSG2 DB 0DH, 0AH, LOWER: $ MSG3 DB 0DH, 0AH, DIGIT: $ DATA ENDS STACK SEGMENT STACK DB 100 DUP(0) STACK ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START: MOV AX, DATA MOV DS, AX CALL INPUT_STR CALL COUNT_CHARS CALL OUTPUT_RESULT MOV AH, 4CH INT 21H INPUT_STR PROC MOV DX, OFFSET BUFFER MOV AH, 0AH INT 21H RET INPUT_STR ENDP COUNT_CHARS PROC MOV CL, BUFFER1 MOV CH, 0 MOV SI, OFFSET BUFFER2 MOV UPPER_CNT, 0 MOV LOWER_CNT, 0 MOV DIGIT_CNT, 0 COUNT_LOOP: CMP CX, 0 JE COUNT_DONE MOV AL, [SI] CMP AL, A JB CHECK_LOWER CMP AL, Z JA CHECK_LOWER INC UPPER_CNT JMP NEXT_CHAR CHECK_LOWER: CMP AL, a JB CHECK_DIGIT CMP AL, z JA CHECK_DIGIT INC LOWER_CNT JMP NEXT_CHAR CHECK_DIGIT: CMP AL, 0 JB NEXT_CHAR CMP AL, 9 JA NEXT_CHAR INC DIGIT_CNT NEXT_CHAR: INC SI DEC CX JMP COUNT_LOOP COUNT_DONE: RET COUNT_CHARS ENDP OUTPUT_RESULT PROC MOV DX, OFFSET MSG1 MOV AH, 09H INT 21H MOV AL, UPPER_CNT CALL PRINT_NUM MOV DX, OFFSET MSG2 MOV AH, 09H INT 21H MOV AL, LOWER_CNT CALL PRINT_NUM MOV DX, OFFSET MSG3 MOV AH, 09H INT 21H MOV AL, DIGIT_CNT CALL PRINT_NUM RET OUTPUT_RESULT ENDP PRINT_NUM PROC PUSH AX PUSH BX PUSH CX PUSH DX MOV AH, 0 MOV BL, 10 DIV BL MOV CL, AH MOV DL, AL ADD DL, 0 MOV AH, 02H INT 21H MOV DL, CL ADD DL, 0 MOV AH, 02H INT 21H POP DX POP CX POP BX POP AX RET PRINT_NUM ENDP CODE ENDS END START测试的时候输入Abc123XY输出应该是UPPER: 3 LOWER: 3 DIGIT: 3这个程序在模拟器上跑通过逻辑是正确的。考试的时候如果出类似的题目你可以直接套用这个框架把统计逻辑换成题目要求的功能就行。5.8 从这个程序里提炼的通用模板这个程序虽然长但可以提炼出一个通用的汇编程序模板。考试的时候不管题目要求什么功能你都可以按这个模板来写DATA SEGMENT ; 数据定义 DATA ENDS STACK SEGMENT STACK DB 100 DUP(0) STACK ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START: MOV AX, DATA MOV DS, AX ; 主程序逻辑 MOV AH, 4CH INT 21H ; 子程序定义 CODE ENDS END START这个模板背下来考试的时候先写模板再填具体逻辑。框架分先拿到手心里就稳了。提示模板里的堆栈段大小可以根据需要调整。如果程序里PUSH操作比较多堆栈段可以定义大一点比如200字节。如果程序很简单100字节足够了。6. 备考节奏和练习方法6.1 分阶段练习计划第四章的内容多不能一口气吃下来。我建议分三个阶段来练习第一阶段专项练习伪指令。花两天时间把DB、DW、DD、EQU、、SEGMENT、ASSUME、PROC、ENDP、ORG、END这些伪指令的格式和用法过一遍。每个伪指令写几个小例子在纸上写然后对照教材检查。这个阶段的目标是看到伪指令能说出它的作用写代码的时候格式不出错。第二阶段专项练习三种程序结构。花三天时间顺序结构一天分支结构一天循环结构一天。每个结构找5到10道题目在纸上写代码然后逐行模拟执行。这个阶段的目标是能独立写出正确的小程序标志位和跳转指令不出错。第三阶段综合练习。花两天时间做完整的编程题。每道题都按考试的要求来先写框架再填逻辑最后检查。做完后对照答案看看哪里扣分了为什么扣分。这个阶段的目标是能在考试时间内完成一道完整的编程题。三个阶段加起来一周左右如果每天能投入3到4小时一周时间足够把第四章拿下。如果时间充裕可以适当延长每个阶段的时间多做几道题。6.2 纸笔练习的具体方法纸笔练习不是随便写写要有方法。我的方法是“三步检查法”第一步写完代码后先检查框架。段定义全不全ASSUME写了没PROC和ENDP配对没END写了没这一步能查出大部分低级错误。第二步逐行模拟执行。从第一条指令开始在纸上画出寄存器和内存的变化。遇到跳转指令根据标志位判断是否跳转。这一步能查出逻辑错误。第三步对照题目要求检查。题目要求的功能实现了没输出格式对不对有没有多余的操作这一步能查出理解偏差。三步检查法看起来很慢但熟练之后一道中等难度的编程题检查一遍只需要5到10分钟。考试的时候这5到10分钟能帮你挽回很多分数。6.3 考试时间分配建议河北专升本的微机原理试卷第四章的题目通常占30到40分。时间分配上我建议选择题和填空题里的第四章题目控制在10分钟内完成。这些题目考的是知识点记忆会就会不会就蒙不要纠结。程序阅读题控制在15分钟内完成。每道题都要逐行模拟不要跳步。编程题控制在25到30分钟内完成。先花5分钟审题和构思再花15分钟写代码最后花5到10分钟检查。如果时间不够优先保证编程题的框架完整。框架分是最好拿的逻辑分拿不到就算了框架分丢了太可惜。6.4 几个考场上的实用技巧第一个技巧拿到编程题先写注释。把题目的要求用注释的形式写在代码框架里比如; 输入10个字符、; 统计大写字母个数、; 输出结果。这样即使代码没写完阅卷老师也能看到你的思路。第二个技巧不确定的指令用伪代码代替。比如你不确定某个地方该用哪个跳转指令可以先写; 判断AL是否大于A然后写一个大概的跳转指令。阅卷老师看到注释可能会给部分分数。第三个技巧代码写完后用题目给的示例数据手动模拟一遍。比如题目说“输入ABC输出3”你就用ABC作为输入在脑子里跑一遍代码看看输出是不是3。如果不对赶紧改。第四个技巧如果实在写不出来把能写的都写上。段定义、ASSUME、PROC、ENDP、END这些框架代码先写上然后把你会的指令都写上。考试是按点给分的写对了就给分写错了不扣分。所以不要留白能写多少写多少。我个人在实际辅导中的体会是第四章的编程题并没有想象中那么难。考试不是让你写一个操作系统而是让你写一个几十行的小程序。只要你把框架背熟把三种结构练熟把常见的输入输出功能记住考试的时候就能写出来。关键是平时要动手写不能只看不练。看十遍不如写一遍写十遍不如在纸上写一遍。纸笔练习虽然原始但最接近考试的真实状态。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑