资讯详情 8086汇编四例:大数相乘、计算器、文本比较与贪吃蛇的避坑指南
📅 2026/10/20 9:42:28
简介北理工《汇编语言与接口技术》课程配套汇编资料覆盖大数相乘、计算器、文本比较与贪吃蛇四个典型项目适合需要完成汇编上机作业或课设的本科生参考。其中大数相乘实现100位以上十进制整数乘法计算器结合Windows界面与浮点编程支持三角函数运算文本比较以Windows界面比对两个文件并输出差异行号贪吃蛇则作为分组游戏程序展示汇编游戏开发思路。资源共241个文件以asm源程序、exe可执行文件、Visual Studio工程文件及bmp/ico等界面资源为主另有docx作业文档便于对照要求压缩包仅608KB结构清晰方便按项目切换使用。目前已有534人学习下载适合边看代码边验证运行结果的初学者深入研习。1. 汇编语言与接口技术课程资料里为什么四个小程序比教材例题更值得啃一门汇编语言与接口技术课学到期末最该留下的不是考点背诵而是几个能跑的程序。某高校课程资料里流传最广的四个汇编实例——大数相乘、计算器、文本比较、贪吃蛇——恰好把 8086 实模式编程里最难缠的五件事全练了一遍进位链、溢出与除零、字符串比较、定时中断、显存操作。很多同学对着教材例题能看懂一动手调这四个程序就翻车原因不是指令不会而是寄存器、标志位、内存布局这些「看不见的状态」没管好。如果你刚开始学汇编这份资料是比教材例题更值得一行行跟下来的训练材料如果你已经调通更会关心参数怎么改、边界在哪。这篇文章按这四个程序拆开讲重点放在动手前必须想清楚的设计选择以及最容易踩坑的位置。2. 大数相乘与计算器竖式乘法、除零保护和溢出判断的汇编实现2.1 大数相乘把竖式乘法搬进寄存器低位在前的数组设计8086 的 MUL 指令一次最多处理 8 位乘 8 位结果 16 位或 16 位乘 16 位结果 32 位超出寄存器宽度的数直接溢出。大数相乘要解决的就是「寄存器装不下」的问题常见做法是模拟手算竖式把一个多字节数按字节分段一个字节相当于十进制里的一位逐位相乘再累加进位。数据布局上我一般用低位在前的数组数组下标 0 存最低字节。为什么低位在前因为进位是向高位走的乘法循环从下标 0 往大走正好顺着进位方向算完第 i 位的进位可以自然加到 i1 位不需要回头。; 大数相乘内层循环核心代码 ; DS:SI 指向被乘数低位在前ES:DI 指向结果数组低位在前 ; AL 被乘数当前字节BL 乘数当前字节外层循环提供 MUL_BYTE: LODSB ; AL 被乘数的一个字节SI 指向下一位 MUL BL ; AX AL * BL8 位乘 8 位结果 16 位 ADD AL, [DI] ; 低字节加上结果数组当前位置的旧值 ADC AH, 0 ; 把低位加法产生的进位补到 AH MOV [DI], AL ; 写回结果数组低位 INC DI ; 指向结果数组下一位 MOV AL, AH XOR AH, AH ; AL 之前乘积的高字节即进位 ADD AL, [DI] MOV [DI], AL ; 若进位继续向更高位传播需要用 ADC 循环处理这里不再展开这段代码的逻辑是LODSB 取被乘数一个字节MUL BL 得到 16 位乘积乘积低字节 AL 要先加上结果数组当前位置已有的值再加上上一位传下来的进位然后写回。乘积高字节 AH 则作为进位累加到下一位。这里有个不太容易注意到的巧劲单次字节乘法最大是 FF × FF FE01加上旧值 FF 和进位 1仍然小于 FFFF所以「MUL → ADD → ADC」三连不会二次溢出。这是按字节分段做乘法能成立的关键很多初版代码在这里用 ADD 不用 ADC导致高位进位丢失结果数组中间出现空洞调试时极其难受。参数上要注意三件事结果数组长度必须大于等于被乘数字节数加乘数字节数否则高位会写穿结果数组在乘法前必须清零否则旧垃圾值会叠加进结果被乘数长度和乘数长度单独存变量不要用固定常量写死。时间复杂度是 O(n×m)属于大数乘法里实现最简单、但不算快的方案教学和课程设计完全够用。2.2 计算器的三个硬骨头键盘输入、表达式顺序和除零保护计算器程序看起来比大数相乘简单实际写起来有三个坎键盘输入方式、表达式处理顺序、除法溢出。键盘输入用 INT 21H 的 AH01H 功能读一个字符并回显回车键的 ASCII 码是 0DH需要单独判断。更稳妥的做法是先用 AH0AH 缓冲输入把整串表达式读进内存再逐字符解析。直接读单个字符会让「两位数输入」变得很难处理因为你要自己拼十位和个位。表达式处理上课程设计最常见的是「单步计算器」输入一个数再输入运算符再输入一个数立即算出结果并显示。这种实现状态机很直观一个变量存当前结果一个变量存待输入操作数。如果要支持「先乘除后加减」就需要操作数栈和运算符栈或者先转逆波兰表达式再计算。用 8086 汇编写栈式解析不是不行但代码量和调试成本直接翻倍。我一般建议先把单步版本跑通再考虑加优先级。; 除法前保护除数为 0 时直接跳错误处理 ; AX 被除数BL 除数结果AL 商AH 余数 CMP BL, 0 JE DIV_ZERO_HANDLER ; 除数为 0跳到错误提示 CMP AH, BL JAE DIV_OVERFLOW ; AH BL 时商必然 256会溢出 DIV BL这段代码很多初学者会漏掉第二重判断。DIV 指令的除零会触发 INT 00H直接终止程序没有任何错误码返回。这个中断向量在实模式下的默认处理就是终止进程所以程序会「悄无声息地没了」。但即便除数不为零还有一个隐藏坑当被除数 AX 的高位 AH 大于等于除数 BL 时商超过一个字节能表示的范围同样触发除法溢出中断。所以除零保护和溢出保护要一起写。有符号数的溢出判断和无符号数不一样无符号加法看 CF 进位标志有符号加法看 OF 溢出标志。8086 里有 JO 指令专门在有符号溢出时跳转。比如两个正数相加结果是负数OF 就会被置 1。计算器如果只做无符号运算可以忽略 OF但一旦涉及负数输入就必须在每次加法和减法后查 OF。2.3 数值转十进制的显示函数除 10 取余和倒序输出乘法、加法的结果在寄存器里都是二进制要显示成十进制必须先转换。16 位二进制数最大 65535转换方法是不断除以 10余数是最低位商继续除直到商为 0然后把所有余数倒序输出。; 把 AX 中的 16 位无符号数转十进制并显示 ; 用栈做倒序存储最后逐字符输出 PRINT_DEC: XOR CX, CX ; CX 统计位数 MOV BX, 10 PUSH_DIGIT: XOR DX, DX ; 必须清零 DXDIV 是 32 位除以 16 位 DIV BX ; DX:AX / 10商在 AX余数在 DX PUSH DX ; 余数压栈 INC CX OR AX, AX JNZ PUSH_DIGIT ; 商不为 0 继续除 PRINT_LOOP: POP DX ADD DL, 0 ; 余数转 ASCII 字符 MOV AH, 02H INT 21H ; 输出一个字符 LOOP PRINT_LOOP RET这里最常见的翻车点是忘记在 DIV 前清零 DX。DIV BX 执行的是 32 位除以 16 位DX:AX 是被除数如果 DX 里残留了上一次运算的值整个除法结果就全错了。栈在这里的用法值得体会先除出的余数是低位最后输出而栈是后进先出正好把余数倒过来这是压栈倒序的经典用法。如果要把大数相乘的结果显示出来不能直接把整个大数放进 AX。常见做法是从高字节到低字节逐段转十进制再拼接输出或者用「除以 10000」的方式把多字节数整体转成十进制。后者更通用但实现起来要写多字节除法属于进阶内容。3. 文本比较从 REPE CMPSB 到不区分大小写的逐字符循环3.1 先定义串的结束判定$ 结尾、回车结尾还是定长补空格写文本比较程序之前第一件事不是写循环而是确定两个字符串怎么算结束。这个决定直接影响比较逻辑。常见的结束方式有三种DOS 键盘缓冲输入默认在字符串末尾加$从终端读入可能以回车换行 0DH 0AH 结尾从定长文件记录读入则是固定长度末尾补空格。以$结尾最简单比较时遇到$说明串结束。以回车换行结尾要处理两个字节而且换行不一定可靠。定长补空格则必须按固定长度比较末尾空格是有效数据不能把空格当结束符处理。课程资料里的文本比较程序多数走$结尾输入用 AH0AH 缓冲读入后自动带这个后缀。先写一个约定第一个串放在 DS:SI第二个串放在 ES:DI。这个约定贯穿整个比较函数调用前必须把两个串的段地址和偏移都设置好尤其是 ES它在很多程序里根本没被初始化过。3.2 REPE CMPSB 的正确设定DF 方向、ES 段寄存器和 CX 长度对定长字符串8086 提供了现成的串比较指令 CMPSB比较 DS:SI 和 ES:DI 指向的一个字节然后 SI、DI 同时自动增减。配合 REPE 前缀可以在相等时不断比较直到遇到不相等或 CX 减到 0。; 比较两个定长字符串是否完全相同 ; DS:SI - 串1ES:DI - 串2CX 字节数 CLD ; DF 0SI/DI 向地址增大方向移动 REPE CMPSB ; 相等则继续不等或 CX0 则停止 JZ STRINGS_EQUAL ; ZF1 表示比较完且全部相等 ; 走到这里说明发现差异 STRINGS_EQUAL: RETREPE CMPSB 的停止条件有两个一是找到不相等字节此时 ZF0二是 CX 减到 0 还没遇到不等此时 ZF1。所以比较结束后直接看 ZF 就能判断是否完全相等。这段代码很短但三个前置条件缺一不可。第一个是 CLD。DF 标志决定 SI/DI 的移动方向如果之前某处执行过 STDDF1两个指针就反着走比较结果完全错乱。第二个是 ES 段寄存器。CMPSB 比较的是 ES:DI 指向的串很多初学者只设置 DS:SI 和 DS:DI忘记 ES:DI 需要先用辅助寄存器加载程序会拿一段随机内存去比。第三个是 CX 长度它必须是比较的字节数不是字符数——纯 ASCII 时两者相等一旦处理汉字就把串长度搞错。3.3 大小写归一和第一处差异定位实际使用中多半要求不区分大小写比较。把字母统一转成小写再比是教科书做法这里有个边界坑直接对任意字节执行 OR AL, 20H会把[0x5BH变成{0x7BH把反斜杠变成|。所以转换前要先判断字节是不是大写字母 AZ是才做转换。; 忽略大小写比较两个以 $ 结尾的字符串 ; DS:SI - 串1ES:DI - 串2 ; 返回AX 首次差异位置完全相同则 AX 0FFFFH STRCMP_IGNORE: XOR CX, CX ; CX 记录当前位置 LOOP_STRCMP: LODSB ; AL 串1 当前字符 MOV BL, [DI] ; BL 串2 当前字符 CMP AL, $ JE CHECK_END1 ; 串1 先结束 CMP BL, $ JE FIND_DIFF ; 串2 先结束判为不同 ; 串1 字符转小写先判断是否大写字母 CMP AL, A JB CONVERT_2 CMP AL, Z JA CONVERT_2 OR AL, 20H CONVERT_2: ; 串2 字符转小写 CMP BL, A JB DO_CMP CMP BL, Z JA DO_CMP OR BL, 20H DO_CMP: CMP AL, BL JNE FIND_DIFF INC DI INC CX JMP LOOP_STRCMP CHECK_END1: CMP BL, $ JNE FIND_DIFF ; 串2 还有字符长度不一致 MOV AX, 0FFFFH RET FIND_DIFF: MOV AX, CX ; 返回差异位置 RET这个逐字符版本的好处是能精确定位差异位置也能处理不定长字符串。CX 从 0 开始计数每比较一个字节加 1遇到差异直接把 CX 给 AX调用方就知道第一次不匹配的下标。输出 AX0FFFFH 是常见的约定值表示「完全一致」避免和合法的差异位置 0 冲突。如果只是想知道两个字符串是否一致、不需要位置REPE CMPSB 的版本更快代码更短。但课程设计题只要写文本比较多半会要求输出差异位置所以逐字符版本更实用。两个版本建议都写一遍体会「指令精简」和「功能完整」之间的取舍。4. 贪吃蛇数组坐标、非阻塞键盘和定时中断组成的完整小游戏4.1 蛇身的数据结构用数组存坐标头进尾出贪吃蛇是四个程序里唯一带「实时性」的它把前面所有知识点串起来了。游戏区域可以设定为 80×25 文本模式每个字符在显存 B800H 段占两个字节低字节是字符 ASCII 码高字节是颜色属性。蛇身用数组存坐标每个节点两个字节列、行。蛇的移动模型有两种常见设计。第一种是「整体搬移」每走一步把蛇身所有节点往后挪一格新头坐标写入下标 0视觉上蛇就前进了。这种方法实现直观蛇最长几十节时速度也完全够用。第二种是「环形数组」用头指针和尾指针维护蛇身每次移动只改头和尾两个位置效率更高但理解成本大。课程资料里的贪吃蛇一般是第一种。; 蛇身数组 SNAKE_BODY 下标 0 存蛇头每节点 2 字节 (COL, ROW) ; SNAKE_LEN 表示当前节点数 ; 先把旧蛇尾坐标保存到 OLD_TAIL用于擦除屏幕上的蛇尾 MOVE_SNAKE: MOV SI, SNAKE_LEN SHL SI, 1 ; SI SNAKE_LEN * 2 MOV AX, SNAKE_BODY[SI-2] MOV OLD_TAIL, AX ; 保存旧蛇尾坐标 MOV CX, SNAKE_LEN DEC CX ; 需要移动的节点数 SNAKE_LEN - 1 MOV SI, CX SHL SI, 1 ; SI (SNAKE_LEN-1) * 2 MOV DI, SI ADD DI, 2 ; DI 比 SI 高一个节点 MOVE_BACK: DEC SI DEC SI ; SI - 2 DEC DI DEC DI ; DI - 2 MOV AX, SNAKE_BODY[SI] MOV SNAKE_BODY[DI], AX LOOP MOVE_BACK ; 从尾部往前复制防止覆盖未移动的源 MOV SNAKE_BODY[0], DX ; DX 新蛇头坐标这段代码的核心是「从尾部往前搬」。如果从头部往后搬先写下标 1再写下标 2 时源数据已经被覆盖成旧头坐标了整个蛇身会变成一坨相同坐标。用 LOOP 从尾部开始逐节点往后复制源和目标不重叠这个坑就避开了。移动后面还要做两件事判断是否吃到食物如果吃到SNAKE_LEN 加 1蛇尾不擦除否则在屏幕上用空格擦掉 OLD_TAIL。这是「头进尾出」的视觉表现。顺序不能反先保存旧蛇尾再移动蛇身否则旧尾坐标就找不回来了。4.2 非阻塞键盘查询与 INT 1CH 定时刷新别让蛇停下来等人游戏循环最忌讳的是用 INT 21H 的 AH01H 读键盘这个调用会阻塞等待按键。一旦执行到它整个游戏就停住蛇不动了直到用户按键才恢复。正确做法是在游戏主循环里「查询」键盘而不是「等待」键盘。; 游戏主循环骨架查询键盘 定时移动 GAME_LOOP: MOV AH, 01H INT 16H ; 查询键盘缓冲区是否有键 JZ NO_KEY ; ZF1 表示无键 MOV AH, 00H INT 16H ; 读取按键AX 中有扫描码和 ASCII 码 ; 根据 AX 判断方向键或 WASD更新方向变量 NO_KEY: CMP TICK_COUNT, 0 JE GAME_LOOP ; 还没到节拍继续查键盘 DEC TICK_COUNT CALL MOVE_SNAKE CALL CHECK_COLLISION CALL UPDATE_SCREEN JMP GAME_LOOP这里用 INT 16H 的 AH01H 功能查询键盘缓冲区有键时 ZF0键码仍然留在缓冲区再用 AH00H 把键取出来。两步配合不会丢键也不会阻塞。方向更新和蛇身移动分开了方向可以每帧都改但移动只在固定节拍发生这样蛇的速度不会因为按键频率变化而忽快忽慢。定时节拍从哪来实模式下的标准做法是接管 INT 1CH。这个中断由系统时钟的 INT 08H 在每次滴答时调用默认只是一个 IRET用户程序可以替换它的中断向量。大约每秒触发 18.2 次对贪吃蛇来说速度合适。; 接管 INT 1CH 的中断服务例程只做标记不做实际刷新 NEW_1CH: PUSH AX PUSH DS MOV AX, DATA_SEG MOV DS, AX INC TICK_COUNT ; 只是把计数器加 1 POP DS POP AX IRET中断服务例程要短。常见做法是只把 TICK_COUNT 加 1所有游戏逻辑在主循环里做。如果把移动、碰撞检测、显存刷新全塞进中断一旦运行时间超过下一个时钟滴答间隔会出现中断重入程序表现就是行为诡异、时好时坏这就是典型的玄学问题。设置新中断向量之前用 INT 21H 的 AH35H 保存旧向量程序退出前用 AH25H 恢复否则中断向量指向已卸载的代码系统随时可能崩溃。4.3 随机食物、撞墙与咬到自己INT 1AH 取种子和边界判定随机食物位置通常用 INT 1AH 的 AH00H 读取时钟计数器返回 CX:DX。这个计数器每秒大约跳 18.2 次取 DX 的低字节当随机数再对游戏区域宽度取余得到食物列坐标。这样实现的随机数没有大问题但分布有偏差尤其是取余后低坐标出现的概率偏高。想要更均匀可以用线性同余生成器把上次随机数乘一个常数再加另一个常数再取低 16 位。对于课程设计时钟计数足够。撞墙判定很简单新蛇头坐标的列小于 0 或大于等于 80行小于 0 或大于等于 25就算撞墙。边界值用 GE/JL 做无符号或有符号比较时要统一坐标用无符号数处理更安全。咬到自己的判定要遍历蛇身但注意不能从蛇头开始比。; 检查新蛇头是否咬到自己 ; DX 新蛇头坐标SNAKE_LEN 为当前长度 CHECK_SELF: MOV CX, SNAKE_LEN DEC CX ; 从下标 1 开始跳过蛇头 MOV SI, 2 ; 下标 1 的字节偏移是 2 CHECK_LOOP: CMP DX, SNAKE_BODY[SI] JE COLLISION ; 与身体某节点坐标相同判为失败 ADD SI, 2 LOOP CHECK_LOOP从下标 1 开始遍历是关键。蛇头本身永远和「新蛇头坐标」相等如果从下标 0 开始游戏一开始就结束了。另外蛇在吃到食物增长的瞬间蛇尾还没移动此时新头坐标不会和旧蛇尾冲突所以这个判定不需要特殊处理。随机食物生成后要和整条蛇身对比避免食物出现在蛇身上否则会出现「食物在蛇身体里」的诡异画面。5. 汇编避坑手记寄存器污染、除零中断、串方向反了、闪屏与进位断链5.1 子程序不保存现场一个 PUSH/POP 引发的循环失控现象计算器连续运算几次后结果开始混乱贪吃蛇偶尔方向乱跳或者某个循环次数莫名变成巨大值。程序逻辑看了很多遍都找不到问题。原因子程序内部修改了调用者还在用的寄存器返回后没有恢复。最典型的是循环计数器 CX。外部用 CX 控制循环次数调用子程序时子程序里也用 LOOP 或者间接修改了 CX返回后外层循环次数变了程序行为自然错乱。解决在子程序入口把所有会修改的寄存器压栈出口按相反顺序弹栈。写成固定模板MY_SUB: PUSH AX PUSH BX PUSH CX ; 子程序主体 POP CX POP BX POP AX RET这个习惯要养成不要说「我这个子程序只用 AX 没关系」。中断服务例程尤其要这么做因为中断可能在任意时刻打断主程序主程序根本不知道自己的寄存器被改了。5.2 DIV 指令除零程序悄无声息退出连提示都看不到现象输入 0 作为除数后程序直接退出没有报错信息。在模拟器里甚至直接弹一个 divide error 的窗口。原因8086 的 DIV 指令遇到除零时会触发 INT 00H。向量表 00H 的默认中断处理就是终止当前程序不存在返回机会。更隐蔽的是商溢出的情况被除数 AX 的高位 AH 大于等于除数 BL 时商超过一个字节能表达的范围同样触发 INT 00H。很多程序除零保护写了溢出判断没写碰到 300/2 这种看似正常的算式照样崩。解决DIV 之前做双重检查。先 CMP 除数是否为 0再 CMP AH 与除数大小两个条件都通过才执行 DIV。商溢出的判断我用无符号比较 CMP AH, BLJAE 跳转这在 8 位除法里是充要条件。16 位除法则要比较 DX 与被除数高位逻辑一样。5.3 串比较方向反了忘写 CLD两个字符串越比越远现象文本比较程序对两个完全相同的字符串报告「不相同」而且差异位置每次都不同看起来毫无规律。用调试器单步看SI 和 DI 的数值变化方向完全相反。原因执行 REPE CMPSB 之前没有执行 CLDDF 标志位残留为 1。DF1 时CMPSB 执行后 SI 和 DI 是递减的两个指针从字符串末尾往开头走比较的位置自然就错位了。DF 是一个很隐蔽的状态它不会被普通运算改变只有 STD 和 CLD 两条指令能设置和清除。解决在所有串操作指令前明确写 CLD除非你有意让指针反向移动。需要反向时用 STD但用完立刻再 CLD 复位。同时要检查 ES 段寄存器有没有设置成第二个串的段地址这也是初学者高频踩坑点。调这类问题最快的路径是在调试器里看 SI、DI 的变化趋势一眼就能判断方向对不对。5.4 贪吃蛇闪屏整屏重绘是元凶只擦尾画头现象蛇每移动一步整个屏幕都闪一下DOSBox 里尤其明显玩几秒眼睛就花了。原因每一帧都做整屏重绘比如用 INT 10H 的滚动功能清屏再把蛇身所有节点重新画一遍。文本模式 80×25 全屏重写一次大约要写 4000 字节虽然单次很快但配合屏幕刷新率就会出现撕裂和闪烁。解决改成增量刷新——每帧只擦旧蛇尾、画新蛇头。旧蛇尾坐标在移动前已经保存到 OLD_TAIL往那个位置写空格即可新蛇头坐标写一个彩色块字符。这样每帧只写两个字符闪烁问题自然消失。非要全屏重绘时用双缓冲先在内存里画好一帧再一次性拷贝到显存可以减轻闪烁但没有增量刷新效果好。5.5 大数相乘出现空洞进位断链和结果数组初值现象乘积结果中间某一位是 0手算却有值或者乘积结果比预期大低位数像是随机垃圾。原因两个常见错误的叠加。第一内层乘法循环里低位加法用了 ADD 而不是 ADC低位向高位的进位丢了。第二结果数组没有清零就开乘旧数据参与累加。甚至有人把进位加到下一位后下一位再加时又溢出进位没有再继续往更高位传这就是「进位断链」。解决养成三个习惯。第一乘之前把结果数组整体清零长度至少是被乘数长度加乘数长度。第二低位加法用 ADD 加旧值用 ADC 补进位标志。第三进位向高位传播时用一个循环而不是只加一次因为最坏情况下进位会连续穿过多个字节。调试时用一个已知的小数据比如 12345 × 6789逐步对照手算竖式能快速定位断链位置。6. 四份代码向可复用方向改造长度前缀、状态循环与中断瘦身四个程序调通之后值得往可复用方向改一版。我把大数相乘的结果数组改成「长度前缀」结构数组第一个字存数据的字节长度后面才是数据本身。这样调用方拿到结果后先读长度再做显示或后续运算不用预先约定最大长度。代价是显示函数要跟着改但换来的是这个乘法函数可以被别的作业复用不用每次重新适配。计算器最有价值的改造是从单步计算升级成栈式表达式解析。用数组模拟栈遇到操作数压栈遇到运算符时先和栈顶运算符比优先级高就压栈低就弹出栈顶运算再压栈。核心逻辑十几行但调试优先级和括号的过程比写单步版本痛苦不少。我在第一次改造时坚持一次只加一个功能先只加「先乘除后加减」再加括号每加一个功能就跑一遍完整测试。文本比较程序建议把结果输出到文件而不是屏幕。用 DOS 文件句柄操作创建一个结果文件把差异位置以文本形式写进去。这样可以用批处理脚本跑多组测试用例自动比对输出不用每次盯着屏幕肉眼检查。贪吃蛇的进阶方向是「中断瘦身」和「速度自适应」。中断服务例程里永远只做 INC TICK_COUNT 这一件事移动和渲染全部放主循环。速度自适应则是在吃到食物后调整 TICK_COUNT 的阈值比如初始每 10 个滴答移动一次随吃到的食物增加逐步缩短到 3 个滴答。这条改动会让游戏可玩性明显上一个台阶。我自己调试这四个程序时养成一个习惯每改完一段先在调试器里 T 几步观察标志位变化再继续往下写。很多看起来像玄学的问题最后都回到标志位或寄存器现场这两件事上。这套资料的精髓不在于让程序跑通而在于跑通之后你能讲清楚每一处进位、每一个跳转、每一次中断是在和谁打交道。希望帮到你。本文还有配套的精品资源点击获取