基于QtSPIM的无符号整数打印及无符号斐波那契序列实现问题
嘿,刚好我之前在QtSPIM里折腾过无符号整数的打印和斐波那契实现,给你分享下解决方案:
1. 在SPIM中打印无符号整数
MIPS官方的系统调用里,syscall 36是专门用来打印无符号整数的(对应printu),但QtSPIM确实经常不支持这个调用,会报“未知系统调用”的错。解决这个问题最可靠的方式是自己实现无符号整数转字符串并打印的函数,完全避开依赖syscall36的坑。
核心思路是用无符号除法(divu)把数字拆成每一位,转成ASCII码后压入栈(因为除法得到的是逆序的数字位),最后从栈中弹出打印,就能得到正确的顺序。这里给你一个可直接用的实现:
.data newline: .asciiz "\n" .text # 测试用例:打印最大的32位无符号数4294967295 main: li $a0, 0xFFFFFFFF jal print_unsigned li $v0, 10 syscall # 函数:print_unsigned # 输入:$a0 = 要打印的无符号整数 # 输出:控制台打印该数和换行 print_unsigned: addi $sp, $sp, -12 sw $ra, 8($sp) sw $s0, 4($sp) sw $s1, 0($sp) move $s0, $a0 li $s1, 10 # 除数固定为10 # 步骤1:把数字的每一位转成ASCII压栈 li $t0, 0 # 记录数字的位数 print_loop: divu $s0, $s1 # 无符号除法:商存$LO,余数存$HI mfhi $t1 # 取出当前位的余数 addi $t1, $t1, 48 # 转成ASCII字符('0'的ASCII是48) addi $sp, $sp, -4 sw $t1, 0($sp) # 压入栈 addi $t0, $t0, 1 mflo $s0 # 更新为商,继续循环 bne $s0, $zero, print_loop # 步骤2:从栈中弹出字符并打印 print_pop: lw $a0, 0($sp) addi $sp, $sp, 4 li $v0, 11 # syscall 11:打印单个字符 syscall addi $t0, $t0, -1 bne $t0, $zero, print_pop # 打印换行符 la $a0, newline li $v0, 4 syscall # 恢复寄存器并返回 lw $s1, 0($sp) lw $s0, 4($sp) lw $ra, 8($sp) addi $sp, $sp, 12 jr $ra
2. 用无符号数实现斐波那契序列(解决溢出和QtSPIM兼容问题)
因为无符号数不需要处理负数,而且能利用32位的全部范围(最大到4294967295),刚好能容纳到第48个斐波那契数(2971215073),第49个就会溢出。我们需要做两件事:用无符号指令实现斐波那契计算,以及检测溢出并停止,同时用上面的print_unsigned函数来打印结果。
关键细节:
- 用
addu做无符号加法:add指令在有符号溢出时会触发异常,而addu不会,适合无符号场景 - 无符号溢出检测:无符号加法中,如果
a + b的结果小于a(或b),说明发生了溢出(因为正常情况下无符号加法结果必然大于等于任意一个加数) - 完全避开syscall36,用自定义的打印函数兼容QtSPIM
完整的实现代码:
.data prompt: .asciiz "请输入要生成的斐波那契数个数:" newline: .asciiz "\n" overflow_msg: .asciiz "警告:发生无符号溢出,停止生成\n" .text main: # 提示用户输入个数 la $a0, prompt li $v0, 4 syscall # 读取输入的整数 li $v0, 5 syscall move $s0, $v0 # $s0 = 要生成的个数n # 初始化斐波那契数:fib(0)=0,fib(1)=1 li $s1, 0 li $s2, 1 li $t0, 0 # 计数器i=0 fib_loop: bge $t0, $s0, exit_fib # 如果i >=n,退出循环 # 打印当前斐波那契数 move $a0, $s1 jal print_unsigned # 计算下一个斐波那契数:next = fib(n) + fib(n-1) addu $s3, $s1, $s2 # 检测溢出:如果next < 当前的fib(n),说明溢出 bltu $s3, $s1, overflow # 更新斐波那契数:fib(n) = fib(n-1),fib(n-1)=next move $s1, $s2 move $s2, $s3 addi $t0, $t0, 1 j fib_loop overflow: # 打印溢出警告 la $a0, overflow_msg li $v0, 4 syscall exit_fib: # 退出程序 li $v0, 10 syscall # 无符号整数打印函数(和上面的实现完全一致) print_unsigned: addi $sp, $sp, -12 sw $ra, 8($sp) sw $s0, 4($sp) sw $s1, 0($sp) move $s0, $a0 li $s1, 10 li $t0, 0 print_loop: divu $s0, $s1 mfhi $t1 addi $t1, $t1, 48 addi $sp, $sp, -4 sw $t1, 0($sp) addi $t0, $t0, 1 mflo $s0 bne $s0, $zero, print_loop print_pop: lw $a0, 0($sp) addi $sp, $sp, 4 li $v0, 11 syscall addi $t0, $t0, -1 bne $t0, $zero, print_pop la $a0, newline li $v0, 4 syscall lw $s1, 0($sp) lw $s0, 4($sp) lw $ra, 8($sp) addi $sp, $sp, 12 jr $ra
这个程序会在生成到溢出的斐波那契数时自动停止,并打印警告,同时所有的无符号数都能正确打印,完全兼容QtSPIM。
内容的提问来源于stack exchange,提问作者Elisa
相关产品推荐
相关产品推荐

