编写降序后升序输出的MIPS递归程序遇异常,求排查
MIPS递归程序无限循环问题排查
问题背景
需要编写一个MIPS程序,接收用户输入的整数n,先输出从n到1的降序数字,再输出从1到n的升序数字(例如输入3时输出“3 2 1 1 2 3”)。已写出C#参考代码,但自行编写的MIPS程序运行时出现无限循环,仅输出初始输入的n,随后输出大量类似地址的数字,需排查错误。
C#参考代码
using System; public static class LearnRecursion { public static void Main() { int n; Console.Write("Enter an integer: "); n = Convert.ToInt32(Console.ReadLine()); RDemo(n); } public static void RDemo(int n) { if (n < 1) { return; } else { Console.Write("{0} ", n); RDemo(n - 1); Console.Write("{0} ", n); return; } } }
待排查的MIPS代码
.data ### Declare appropriate strings and the space character for I/O prompts ### input: .asciiz "Enter an integer : " space: .asciiz " " newline: .asciiz "\n" .text main: ### call procedure for printing the user prompt ### li $v0, 4 la $a0, input syscall #read input from user li $v0, 5 syscall move $s0, $v0 #store the user input into saved register move $a0, $s0 #move saved user input integer as argument for RDemo jal RDemo j exit # recursive RDemo method # excpects integer argument (from user input) in $a0 #returns when n<1 RDemo: #make space for 4 registers on the stack addi $sp, $sp, -12 sw $ra, 0($sp) #return adress sw $s0, 4($sp) #saved register (original n) sw $a0, 8($sp) #argument (user parsed n) #base case: n < 1 return blez $a0, RDemoReturn #print n li $v0, 1 move $a0, $a0 syscall la $a0, space li $v0, 4 syscall #call RDemo with n-1 addi $a0, $a0, -1 jal RDemo li $v0, 1 move $a0, $s0 #$s0 or $a0 ? syscall la $a0, space li $v0, 4 syscall RDemoReturn: lw $ra, 0($sp) lw $s0, 4($sp) lw $a0, 8($sp) addi $sp, $sp, 12 jr $ra exit: li $v0, 10 syscall
错误分析与修正
核心错误点
递归参数被错误覆盖导致无限循环
打印完n后,执行la $a0, space把$a0改成了字符串的内存地址,后续addi $a0, $a0, -1是对地址做减法,而非原来的n值减1。这会导致递归调用时传入的参数始终是非零值,永远触发不了blez $a0, RDemoReturn的基准情况,从而无限递归。寄存器使用逻辑错误
- 递归返回后打印n时,错误使用了$s0,但$s0保存的是调用者的寄存器值,并非当前函数的n;应该从栈中恢复当前的n值。
- 冗余指令
move $a0, $a0完全无效,可删除。
修正后的MIPS代码
.data input: .asciiz "Enter an integer : " space: .asciiz " " newline: .asciiz "\n" .text main: # 打印输入提示 li $v0, 4 la $a0, input syscall # 读取用户输入 li $v0, 5 syscall move $s0, $v0 move $a0, $s0 jal RDemo j exit # 递归函数RDemo:参数$a0为当前n值 RDemo: # 栈上分配空间,保存返回地址、调用者的$s0、当前n值 addi $sp, $sp, -12 sw $ra, 0($sp) sw $s0, 4($sp) sw $a0, 8($sp) # 先把当前n值存入栈,后续操作不会覆盖 # 基准情况:n<=0时返回 blez $a0, RDemoReturn # 打印当前n li $v0, 1 # $a0此时还是当前n,直接打印 syscall # 打印空格 la $a0, space li $v0, 4 syscall # 递归调用RDemo(n-1):先从栈中取出原来的n值,减1后传入 lw $t0, 8($sp) addi $a0, $t0, -1 jal RDemo # 递归返回后,打印当前n:从栈中恢复当前n值 li $v0, 1 lw $a0, 8($sp) syscall # 打印空格 la $a0, space li $v0, 4 syscall RDemoReturn: # 恢复寄存器,释放栈空间 lw $ra, 0($sp) lw $s0, 4($sp) lw $a0, 8($sp) addi $sp, $sp, 12 jr $ra exit: li $v0, 10 syscall
内容的提问来源于stack exchange,提问作者Ferdinand School
相关产品推荐
相关产品推荐

