MIPS汇编罗马数字解码器调试求助:地址越界与死循环问题
MIPS罗马数字解码器代码问题分析与解决思路
第一版代码:地址超出范围错误
问题现象
运行时触发“地址超出范围”错误,且无法正确返回解码结果。
错误原因
- 循环终止条件错误:仅判断下一个字符是否为
\0,未处理当前字符为\0的情况。当索引指向字符串结束符\0时,程序仍会继续循环,越界访问内存区域,触发地址错误。 - 结果未存入返回寄存器:
exit标签处未将计算结果$t0移动到返回寄存器$v0,导致main函数无法获取正确解码值。 - 字符遗漏处理:当处理最后一个字符时,因下一个字符是
\0,程序直接跳转到exit,导致最后一个字符未被解码累加。
解决思路
- 修改循环终止逻辑:先检查当前字符是否为
\0,若是则立即退出循环,避免越界访问。 - 在
exit标签处添加move $v0, $t0,将结果存入返回寄存器$v0。 - 调整处理顺序:先获取当前字符并判断是否终止,再根据下一个字符的值决定加减操作,确保所有字符都被处理。
修正后的核心循环示例:
roman: li $t0, 0 # 初始化结果 move $t1, $a0 # 保存输入字符串指针 roman_decoder: lb $t2, 0($t1) # 加载当前字符 beqz $t2, exit # 当前字符为\0,退出循环 lb $t3, 1($t1) # 加载下一个字符 move $a0, $t2 jal romdigit # 解码当前字符 move $t4, $v0 # 保存当前字符的值 beqz $t3, add_digit # 下一个字符为\0,直接累加当前值 move $a0, $t3 jal romdigit # 解码下一个字符 bgt $v0, $t4, subtract_digit # 下一个值更大,执行减法 add_digit: add $t0, $t0, $t4 addi $t1, $t1, 1 j roman_decoder subtract_digit: sub $t0, $t0, $t4 addi $t1, $t1, 2 # 跳过下一个字符,后续不再处理 j roman_decoder exit: move $v0, $t0 jr $ra
第二版代码:程序无法终止
问题现象
程序陷入循环无法终止,无法回到main函数结束执行。
错误原因
- 返回地址寄存器未保存:
roman函数调用romdigit时,jal romdigit会覆盖$ra寄存器的值(原本存储main函数的返回地址)。当执行exit标签处的jr $ra时,会跳回romdigit调用后的指令,而非main函数,形成死循环。 - 解码逻辑冗余:采用“当前值与前一个值比较”的方式,虽部分场景结果正确,但不符合罗马数字“当前值小于下一个值则减”的常规解码逻辑,易引发理解偏差和潜在错误。
解决思路
- 保存与恢复返回地址:在
roman函数入口处,将$ra保存到栈中,调用romdigit后再恢复$ra,确保能正确返回main函数。MIPS栈操作示例:roman: addi $sp, $sp, -4 # 分配栈空间 sw $ra, 0($sp) # 保存$ra到栈 # ... 原有逻辑 ... exit: move $v0, $t2 lw $ra, 0($sp) # 恢复$ra addi $sp, $sp, 4 # 释放栈空间 jr $ra - 调整解码逻辑:改为常规的“当前值与下一个值比较”的方式,逻辑更清晰,便于维护。例如:遍历字符串时,先获取当前字符和下一个字符的值,若当前值小于下一个值则减去当前值,否则加上当前值,同时根据情况移动指针。
内容的提问来源于stack exchange,提问作者checkchecker
相关产品推荐
相关产品推荐

