You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写降序后升序输出的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

错误分析与修正

核心错误点

  1. 递归参数被错误覆盖导致无限循环
    打印完n后,执行la $a0, space把$a0改成了字符串的内存地址,后续addi $a0, $a0, -1是对地址做减法,而非原来的n值减1。这会导致递归调用时传入的参数始终是非零值,永远触发不了blez $a0, RDemoReturn的基准情况,从而无限递归。

  2. 寄存器使用逻辑错误

    • 递归返回后打印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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:40:38