为何emu8086下8086汇编年龄判断程序输入不同值总输出最后一条消息
emu8086 8086汇编年龄分段判断程序bug修正
问题描述
- 程序设计目标:读取用户输入的姓名、学号、年龄,按年龄区间输出对应身份提示
- 实际运行现象:无论输入何种年龄值,仅输出老年提示(
you are old) - 原程序代码:
org 100h INCLUDE 'emu8086.inc' jmp start1 ; 程序入口跳转 ;======================== msg1 db " Program Converter umur" ,13,10,13,10,'$' msg2 db " Nama : $" msg3 db " NIM : $" msg4 db " input your age : $" msg5 db " you are baby $" msg6 db " you are kids $" msg7 db " you are teen $" msg8 db " you are adult $" msg9 db " you are old $" start1: LEA DX,msg1 MOV AH,9 INT 21H PUTC 13 PUTC 10 start2: LEA DX,msg2 MOV AH,9 INT 21H CALL GET_STRING PUTC 13 PUTC 10 start3: LEA DX,msg3 MOV AH,9 INT 21H CALL GET_STRING PUTC 13 PUTC 10 start4: LEA DX,msg4 MOV AH,9 INT 21H CALL GET_STRING PUTC 13 PUTC 10 CMP CX,5 JB baby JE baby CMP CX,10 JB kids JE kids CMP CX,20 JB teen JE teen CMP CX,50 JB adult JE adult JA old baby : LEA DX,msg5 MOV AH,9 INT 21h PUTC 13 PUTC 10 kids : LEA DX,msg6 MOV AH,9 INT 21h PUTC 13 PUTC 10 teen : LEA DX,msg7 MOV AH,9 INT 21h PUTC 13 PUTC 10 adult : LEA DX,msg8 MOV AH,9 INT 21h PUTC 13 PUTC 10 old : LEA DX,msg9 MOV AH,9 INT 21h PUTC 13 PUTC 10 MOV AH,0 INT 16H ret
错误原因分析
- 年龄数值获取错误:emu8086 的
GET_STRING宏返回的CX是输入字符串的字符个数(例如输入年龄“25”时,CX=2),而非输入数字的二进制值,直接用CX做区间比较完全无效。 - 分支穿透问题:
baby、kids、teen、adult分支的代码执行完成后,没有跳转到程序结束指令,会直接顺序执行后续分支的代码,最终必然走到old分支,输出老年提示。 - 输入缓冲区未定义:
GET_STRING宏需要指定输入缓冲区(用于存储用户输入的字符),原代码未定义缓冲区,也未将DI指向缓冲区,导致输入操作的结果不可控。
修正方案
- 新增ASCII字符串转二进制数值的逻辑:将输入的年龄ASCII字符(例如“25”)转换为对应的16位二进制值(
0019h)。 - 定义输入缓冲区:为姓名、学号、年龄的输入分别定义缓冲区,符合
GET_STRING宏的调用要求。 - 分支终止跳转:每个身份分支执行完成后,添加
jmp exit指令跳转到程序结束,避免分支穿透。 - 用转换后的年龄寄存器(例如
AX)做区间比较,而非字符个数CX。
修正后程序代码
org 100h INCLUDE 'emu8086.inc' ; 定义输入缓冲区(符合GET_STRING要求:首字节=最大字符数,次字节=实际输入数,后续=字符存储) name_buf db 20, ?, 20 dup(?) ; 姓名缓冲区:最多19个字符 nim_buf db 20, ?, 20 dup(?) ; 学号缓冲区:最多19个字符 age_buf db 3, ?, 3 dup(?) ; 年龄缓冲区:最多2个字符(支持1-99岁) jmp start1 ; 程序入口跳转 ;======================== msg1 db " Program Converter umur" ,13,10,13,10,'$' msg2 db " Nama : $" msg3 db " NIM : $" msg4 db " input your age : $" msg5 db " you are baby $" msg6 db " you are kids $" msg7 db " you are teen $" msg8 db " you are adult $" msg9 db " you are old $" start1: LEA DX,msg1 MOV AH,9 INT 21H PUTC 13 PUTC 10 ; 读取姓名 start2: LEA DX,msg2 MOV AH,9 INT 21H LEA DI, name_buf ; 指向姓名缓冲区 CALL GET_STRING PUTC 13 PUTC 10 ; 读取学号 start3: LEA DX,msg3 MOV AH,9 INT 21H LEA DI, nim_buf ; 指向学号缓冲区 CALL GET_STRING PUTC 13 PUTC 10 ; 读取年龄 start4: LEA DX,msg4 MOV AH,9 INT 21H LEA DI, age_buf ; 指向年龄缓冲区 CALL GET_STRING PUTC 13 PUTC 10 ; --- 新增:将年龄ASCII字符串转为二进制数值(存在AX) --- MOV AX, 0 ; 初始化年龄数值为0 MOV CL, age_buf[1] ; 实际输入的年龄字符数(CX低8位) MOV CH, 0 ; CX=实际输入字符数 MOV SI, 2 ; SI指向年龄缓冲区的第一个字符(age_buf[2]) convert_age: MOV BX, AX ; 保存当前数值 MOV AX, 10 MUL BX ; 当前数值*10(处理两位数:例如先算2*10=20,再加5) MOV BL, age_buf[SI]; 取当前ASCII字符(例如'5'=35h) SUB BL, 30h ; 转成数字(35h-30h=5) MOV BH, 0 ADD AX, BX ; 累加数值 INC SI DEC CX JNZ convert_age ; 循环直到所有字符处理完成 ; --- 区间比较(用AX=年龄数值) --- CMP AX, 5 JB baby JE baby CMP AX, 10 JB kids JE kids CMP AX, 20 JB teen JE teen CMP AX, 50 JB adult JE adult JA old baby : LEA DX,msg5 MOV AH,9 INT 21h PUTC 13 PUTC 10 JMP exit ; 跳转终止,避免穿透 kids : LEA DX,msg6 MOV AH,9 INT 21h PUTC 13 PUTC 10 JMP exit ; 跳转终止 teen : LEA DX,msg7 MOV AH,9 INT 21h PUTC 13 PUTC 10 JMP exit ; 跳转终止 adult : LEA DX,msg8 MOV AH,9 INT 21h PUTC 13 PUTC 10 JMP exit ; 跳转终止 old : LEA DX,msg9 MOV AH,9 INT 21h PUTC 13 PUTC 10 ; 程序结束 exit: MOV AH,0 INT 16H ; 等待按键 ret
内容的提问来源于stack exchange,提问作者muhammad fahrizal
相关产品推荐
相关产品推荐

