在MIPS中实现给定排序与交换函数时,无需将参数保存至$S寄存器或栈是否合理?
你的理解存在一些关键误区,我们结合MIPS寄存器调用约定和你的代码逻辑来逐一拆解分析:
1. 先明确MIPS寄存器的核心调用规则
- 临时寄存器($t0-$t9):被调用函数(比如这里的
swap)可以随意修改这些寄存器的值,调用函数(sort)不能假设调用后这些寄存器还保留原有内容。 - 保存寄存器($s0-$s7):如果被调用函数要修改这类寄存器,必须先把原值压栈保存,调用结束后恢复;调用函数可以放心地在调用其他函数前后使用这些寄存器的内容。
- 参数寄存器($a0-$a3):属于临时寄存器范畴,调用其他函数后,这些寄存器的值大概率会被覆盖,调用函数不能依赖它们保留初始参数值。
2. 分析
sort函数对寄存器的实际需求 先回顾你的C代码逻辑:
void sort (int v[], int n) { int i, j; for (i = 0; i<n; i+=1){ for(j=i-1; j>=0 && v[j]>v[j+1]; j-=1){ swap(v,j); } } }
- 参数
v:它是数组的指针地址,整个sort执行过程中这个地址是固定的(只有数组内容会被swap修改)。每次调用swap都需要传递这个地址,但如果把它存在$a0里,调用swap后,$a0可能被swap修改(哪怕你的swap汇编没改,按调用约定swap有权修改),后续sort就无法再定位到数组了。 - 参数
n:数值全程固定,外层循环每次都要靠它判断i < n。如果把n存在$a1里,调用swap时会把$a1覆盖成j的值(因为swap的第二个参数是j),调用结束后n的数值就丢失了,外层循环无法继续执行。 - 循环变量
j:调用swap后还需要执行j -= 1,如果j存在临时寄存器(比如$t系列)里,swap可能会修改这个寄存器的值,导致j的数值丢失,内层循环无法正常迭代。
3. 为什么必须把这些值存入
$s寄存器或栈 你提到的“v[]在swap函数中需要保持修改后的状态”和保存指针地址是两回事:我们要保存的是数组的指针值(不是数组内容),数组内容的修改是通过指针操作的,保存指针地址是为了确保sort在调用swap后还能正确找到数组的位置。
而循环变量j的问题在于,swap会使用临时寄存器,如果你把j存在临时寄存器里,调用swap后这个寄存器的值可能被覆盖,导致j的数值丢失,内层循环无法继续推进。
正确的做法是:
- 在
sort函数入口处,把$a0(v的地址)保存到$s0,把$a1(n的数值)保存到$s1(按规则,需要先把$s0和$s1的原值压栈,再存入新值)。 - 循环变量
i和j可以用临时寄存器,但在调用swap之前,需要把j的值保存到不会被修改的地方(或者调用swap时把j放到$a1,调用结束后从栈/保存寄存器里恢复j的值)。
4. 你的
swap汇编代码的小错误 顺便纠正一个逻辑问题,你的swap汇编里的地址计算有误:
swap : sll $t1, $a0, 2 // 注释写的是k*4,但$a0是v的地址,k应该对应$a1 add $t1, $a0, $t1 // 这行的地址计算逻辑也错了
正确的swap汇编应该是:
swap : sll $t1, $a1, 2 # $t1 = k * 4(int类型占4字节) add $t1, $a0, $t1 # $t1 = v的起始地址 + k*4 = &v[k] lw $t0, 0($t1) # $t0 = v[k](临时存储) lw $t2, 4($t1) # $t2 = v[k+1] sw $t2, 0($t1) # v[k] = v[k+1] sw $t0, 4($t1) # v[k+1] = 临时存储的v[k] jr $ra # 返回调用者
内容的提问来源于stack exchange,提问作者user9178840
相关产品推荐
相关产品推荐

