请翻译带MIPS汇编注释的冒泡排序C代码并完善对应汇编实现
嘿,我来帮你梳理MIPS里减法相关的条件分支逻辑,同时把那段冒泡排序的C代码补全并翻译成中文,再给出完整的MIPS汇编实现~
MIPS汇编减法条件分支说明与冒泡排序实现
一、MIPS减法相关条件分支指令说明
在MIPS汇编中,没有直接的减法比较分支指令,通常通过设置小于测试指令结合分支指令来实现类似“大于/等于”的条件判断(本质是通过反向判断小于关系来推导):
slt rd, rs, rt:若寄存器rs的有符号值小于rt,则将rd设为1,否则设为0;sltu rd, rs, rt:无符号版本的小于测试,逻辑同上,但按无符号数规则比较;beq rd, $0, label:若rd的值为0,就跳转到label标签处。
举个实际场景:要实现C代码中的if(i >= N) goto Endl,我们可以拆解为:
- 先用
slt $t0, $s0, $s1(假设$s0存i,$s1存N)判断i < N:如果成立,$t0=1;否则$t0=0; - 再用
beq $t0, $0, Endl:当$t0=0时,说明i >= N,此时跳转到Endl。
这样就完美实现了“大于等于”的分支逻辑,相当于用减法的反向比较来完成判断。
二、带MIPS注释的冒泡排序C代码(完整补全+翻译)
你提供的代码是未完成的冒泡排序片段,我先补全核心逻辑,同时把注释翻译成中文:
#include <stdio.h> int arr[5] = {5, 3, 4, 1, 2}; // 待排序的整数数组 int main(){ int k; int N = 5, i, j; char * parr0 = (char*) arr; /* MIPS对应指令:la parr0, arr (加载数组基地址到parr0寄存器)*/ char * parrj; i = 0; for1: if(i >= N) goto Endl; /* MIPS对应逻辑:slt $t0, $s0, $s1 ($s0=i,$s1=N);beq $t0, $0, Endl (如果i>=N则跳转到Endl)*/ j = 0; for2: if(j >= N-1-i) goto End2; // 内层循环终止条件:j >= 未排序部分的长度 parrj = (parr0 + 4*j); // 计算arr[j]的地址(int占4字节,所以偏移4*j) int x1 = *((int*)parrj); /* MIPS对应指令:lw $t1, 0($t2) ($t2是parrj,加载arr[j]到$t1寄存器,替代C中的arr[j])*/ int x2 = *((int*)(parrj+4)); /* MIPS对应指令:lw $t2, 4($t2) (加载arr[j+1]到$t2寄存器,对应arr[j+1])*/ // 补全冒泡排序核心逻辑:比较并交换相邻元素 if(x1 > x2){ // 交换arr[j]和arr[j+1] *((int*)parrj) = x2; *((int*)(parrj+4)) = x1; } j++; goto for2; End2: i++; goto for1; Endl: // 打印排序后的数组 for(k=0; k<N; k++){ printf("%d ", arr[k]); } return 0; }
三、完整MIPS汇编实现(对应上述冒泡排序)
以下是基于MIPS32架构的完整汇编代码,包含数据段、代码段,每一步都有详细注释:
.data arr: .word 5, 3, 4, 1, 2 # 待排序的整数数组 N: .word 5 # 数组长度 newline:.asciiz "\n" space: .asciiz " " .text .globl main main: la $s0, arr # $s0 = arr基地址(对应C中的parr0) lw $s1, N # $s1 = N = 5 li $s2, 0 # $s2 = i = 0 # 外层循环:对应C中的for1标签 for1: slt $t0, $s2, $s1 # 判断i < N?是则$t0=1,否则0 beq $t0, $0, print_result # 如果i >= N,跳转到打印结果(对应原代码的Endl) li $s3, 0 # $s3 = j = 0 sub $t1, $s1, 1 # $t1 = N-1 sub $t1, $t1, $s2 # $t1 = N-1 - i(内层循环终止条件值) # 内层循环:对应C中的for2标签 for2: slt $t0, $s3, $t1 # 判断j < N-1-i?是则$t0=1,否则0 beq $t0, $0, end_for2 # 如果j >= N-1-i,跳转到end_for2(对应原代码的End2) sll $t2, $s3, 2 # $t2 = 4*j(int占4字节,左移2位等价乘4) add $t3, $s0, $t2 # $t3 = parr0 + 4*j = &arr[j] lw $t4, 0($t3) # $t4 = arr[j](对应C中的x1) lw $t5, 4($t3) # $t5 = arr[j+1](对应C中的x2) slt $t0, $t5, $t4 # 判断arr[j+1] < arr[j]?是则$t0=1(即arr[j] > arr[j+1]) beq $t0, $0, increment_j # 如果arr[j] <= arr[j+1],不交换,直接j++ # 交换arr[j]和arr[j+1] sw $t5, 0($t3) sw $t4, 4($t3) increment_j: addi $s3, $s3, 1 # j++ j for2 # 回到内层循环开头 end_for2: addi $s2, $s2, 1 # i++ j for1 # 回到外层循环开头 # 打印排序后的数组 print_result: li $s2, 0 # 重置i为0,用于遍历打印 print_loop: slt $t0, $s2, $s1 beq $t0, $0, exit_program sll $t2, $s2, 2 add $t3, $s0, $t2 lw $a0, 0($t3) # 加载当前数组元素到$a0 li $v0, 1 # 系统调用:打印整数 syscall la $a0, space # 打印空格分隔元素 li $v0, 4 syscall addi $s2, $s2, 1 j print_loop exit_program: la $a0, newline # 打印换行 li $v0, 4 syscall li $v0, 10 # 退出程序系统调用 syscall
关键细节说明:
- 数组访问:MIPS中没有直接的数组下标访问,通过基地址+偏移量实现,用
sll(左移2位)来快速计算4*j(因为int占4字节); - 条件分支:所有“大于/等于”的判断都通过
slt反向推导,配合beq实现跳转; - 系统调用:使用MIPS标准的系统调用号来实现打印和退出,符合SPIM/MARS模拟器的运行规范。
内容的提问来源于stack exchange,提问作者TKD21
相关产品推荐
相关产品推荐

