c - C 到 MIPS 汇编 while 循环
问题描述
C语言
while (save[i] == k)
i += 1;
i→ $s3
k → $s5
base addr of save → $s6
sll $t1, $s3, 2 #$t1 = 4*$s3
add $t1, $t1, $s6 #$t1 = address of save[i]
lw $t0, 0($t1) #t0 = save[i]
bne $t0, $s5, Exit #$t0!=$s5 Exit
Loop: addi $s3, $s3, 1 #i+=1
addi $t1, $t1, 4 #point to next cell
lw $t0, 0($t1) #t0 = save[i]
beq $t0, $s5, Loop #$t0==$s5 loop again
Exit:
我想问的是,是否需要addi $s3, $s3, 1行?
因为,无论如何 $ t1 增加了 4。
解决方案
C 代码和汇编代码实际上并不匹配。汇编代码已被优化为使用指针而不是数组引用,并且循环的退出条件也已在循环外复制一次,从而允许循环结构使用更有效的 do while 循环(在迭代期间更有效,因为它与 while 循环的直接代码相比,在末尾保存了一个无条件分支)。
请注意,这些优化不仅在汇编中是可能的,而且在 C 中也是可行的。
程序集的 C 版本如下:
int *sp = save + i; // in C this addition is automatically scaled by 4
if ( *sp == k ) {
do {
i++;
sp++; // this C +1 is scaled so really is +4
} while ( *sp == k );
}
当然,这在逻辑上等价于另一个。
你的问题是:我们需要i++;
吗?
一个答案是:不,不在循环中。您是正确的,循环不使用i
并且会访问数组的相同元素,并在与原始的更简单的 C 循环相同的点退出。
另一个答案是:是的,如果i
在循环之后使用! 这个循环做的很少,但会检查一些内存。我们不得不问:循环的目的是什么,如果不是为i
循环后面的一些代码设置?在这里,循环的目的可能是计算重复项,这将导致i
成为循环的“输出”/期望结果:在结束时包含重复项的计数,然后运行下一条语句。
这就是为什么很难对小段代码进行推理的原因之一——本质上我们无法判断接下来会发生什么以及是否i
会被使用。但是如果i
不使用,那么循环就没有价值了..
如果我们要尝试将其放入编译器中,我们将被迫将代码段更改为完整的函数。编译器不会接受小于函数的代码语句。
完整的函数定义是您可以提供给编译器的最小代码段(函数定义之外的代码片段在 C 语言中不是合法的语句),并且包装使代码片段的环境变得清晰:
- 参数是给定的输入
- 局部变量是临时的并且超出范围
- 返回值是预期的输出。
(当然也有副作用,例如,排序比函数更持久的东西,或者创建比函数更持久的堆对象。)
包装在一个函数中,然后我们可以确定地观察i
在循环之后是否使用了局部变量。
当然,还有另一种方法可以i
在循环之后计算 ' 的值,而无需在循环期间增加它。在循环之后,以下语句将恢复i
应具有的值:
i = sp - save; // NB: C pointer subtraction automatically descales
在汇编中,这将是减法,然后右移 2 以从字节差值到整数索引值。
(请注意,这些优化和转换很容易被淘汰,因此请检查工作。)
推荐阅读
- c - getchar() 在 while 循环中用作条件时如何工作
- java - JBoss 到 Spring Boot 和 Spring Security 升级:X509 身份验证问题
- python - 从 CSV 文件写入 CSV 文件
- android - 如何解决 RecyclerView 和 OnClickAdapter 的问题?
- graph - 具有互斥边的二部图中的完美匹配
- hana - 如果满足条件,Hana 是否只能允许用户查看视图的特定行
- html - 高度和填充 CSS 属性不适用于搜索输入元素
- sql - 当我尝试将单词与与日期 sql plus 相关的方程连接时
- math - 我如何将多项式拟合到给定范围内的给定点集?(最好不用电脑手动完成)
- powershell - Powershell 停止处理许多实例