使用8086汇编求第n个斐波那契数时陷入无限循环问题排查
斐波那契数求解的8086汇编问题
需求与伪代码
需求是求解第n个斐波那契数(示例:n=3时输出1),设计的伪代码如下:
a = 0 b = 1 input n si = 0 if n>2: loop: temp = b b = a+b a = temp loop while si != cx print b
8086汇编实现代码
在EMU 4.08中编写的汇编代码:
.MODEL SMALL .STACK 100h .DATA STRING0 DB 'Enter INDEX $' .CODE MAIN PROC MOV AX,@DATA MOV DS,AX LEA DX, STRING0 MOV AH,9 INT 21H MOV AH, 2 MOV DL,0AH ; NEW LINE INT 21H MOV DL,0DH INT 21H MOV AH,1 INT 21H SUB CX,CX MOV CL,AL MOV SI,0 MOV AX,0 MOV BX,1 LOOP1: PUSH BX ADD BX,AX POP AX INC SI LOOP LOOP1 MOV DX,BX MOV AH,9 INT 21H MAIN ENDP END MAIN
遇到的问题
- 运行代码时陷入无限循环,无法定位原因
- 使用
SUB CX,CX清空CX后将AL的值移入CL作为计数器,避免8位数据传入16位寄存器的错误,该操作是否合理?
问题分析与修复
1. 无限循环的核心原因
- 输入值未转换为数值:
INT 21H AH=1读取的是字符的ASCII码(比如输入数字3,AL为0x33即十进制51),而非真实数值。直接将该值赋值给CL,会导致循环执行次数远大于预期;若输入字符导致CX初始为0,LOOP指令会将CX减为0xFFFF,触发无限循环。 - 循环控制逻辑混乱:伪代码中想用SI与CX比较控制循环,但8086的
LOOP指令本身通过CX自减并判断是否为0来控制循环,额外的INC SI完全多余且未参与任何判断,逻辑冲突。 - 输出功能错误:
AH=9是DOS输出字符串的功能,要求DS:DX指向以$结尾的字符串。直接将斐波那契数值存入DX,会导致程序访问非法内存,引发异常,表现为看似无限循环的错误。
2. 关键修复点
- ASCII转数值:读取输入后执行
SUB CL, 30H,将字符ASCII码转换为对应十进制数值。 - 修正循环次数:根据需求(n=3输出1),数列定义为第1项0、第2项1,第n项需循环
n-2次计算。先判断n是否≤2,是则直接输出对应值;否则设置CX为n-2,用LOOP控制循环。 - 优化计算逻辑:用临时寄存器替代栈操作保存中间值,逻辑更清晰:
MOV DX, AX→MOV AX, BX→ADD BX, DX。 - 数值转字符串输出:将二进制斐波那契数转换为ASCII字符串后,再用
AH=9输出。
修复后的完整代码
.MODEL SMALL .STACK 100h .DATA STRING0 DB 'Enter INDEX $' RESULT_STR DB 10 DUP('$') ; 存储转换后的ASCII结果 .CODE MAIN PROC MOV AX,@DATA MOV DS,AX ; 打印输入提示 LEA DX, STRING0 MOV AH,9 INT 21H ; 换行 MOV AH, 2 MOV DL,0AH INT 21H MOV DL,0DH INT 21H ; 读取输入字符 MOV AH,1 INT 21H SUB CX,CX MOV CL,AL SUB CL,30H ; ASCII码转十进制数值 MOV AX,0 ; 第1项斐波那契数 MOV BX,1 ; 第2项斐波那契数 ; n≤2时直接输出对应值 CMP CL,2 JBE PRINT_RESULT ; 设置循环次数为n-2 SUB CL,2 MOV CX,CX LOOP1: ; 计算下一项:temp=AX, AX=BX, BX=BX+temp MOV DX,AX MOV AX,BX ADD BX,DX LOOP LOOP1 PRINT_RESULT: ; 将BX中的二进制数转为ASCII字符串 LEA SI, RESULT_STR+9 ; 从字符串末尾开始填充 MOV CX,10 CONVERT: XOR DX,DX DIV CX ADD DL,30H MOV [SI],DL DEC SI CMP AX,0 JNE CONVERT ; 输出结果 LEA DX, RESULT_STR MOV AH,9 INT 21H ; 程序正常退出 MOV AH,4CH INT 21H MAIN ENDP END MAIN
关于SUB CX,CX的说明
该操作完全合理:CX是16位寄存器,直接给CL赋值时CH的值未初始化(为随机垃圾值),SUB CX,CX等价于MOV CX,0,可将CX整体清零,再给CL赋值后,能保证CX的高8位为0,低8位为输入的有效数值,避免16位寄存器高字节的垃圾值影响循环次数。
内容的提问来源于stack exchange,提问作者EmployedSlaveStudent
相关产品推荐
相关产品推荐

