P2-MIPS汇编¶
问题¶
怎么用 li $v0, 12 读字符串并存入字符串数组?
课下¶
闲言碎语
课下花了很长很长的时间 debug,全排列 (周二晚上) & 地图 (周三上午) & 高精度乘法 (周三下午+晚上),我觉得我出错的原因在于,没有正确地使用宏。我本来以为用宏封装,能让代码更清楚,正确率更高,然而事实相反—— 高精度乘法没用宏写,只花了十几分钟,并且成功了一部分数据 (其他就不是 MIPS 使用的问题了,是 C 代码的问题),所以使用宏的时候一定要清醒细心!
递归¶
在函数调用的时候 push,调用完立刻 pop
注意 syscall 的时候可能会改 $a0 ,也要压进栈
常用的宏¶
- 二维数组取地址
- 读入和输出整数
- 进栈出栈
- 输出空白和换行
宏的使用¶
宏不应该改变除 %des 以外的寄存器的值
eg. 输出换行的代码中 la $a0, space 修改了 $a0 ,在有函数调用的时候,会出现矛盾。稳妥写法:
宏中出现过的寄存器就不能设为 des ,get 一定不行,set 要判断,所以最好避免
eg1. 如果调用 getVis($t3, $t0) , $t3 最后弹出原来的值
eg2. 若 %des = $t3 , sll $t3, %pos, 2 改变了本来想填的 $t3 的值,错误
字符和字符串¶
- 字符串读入—8
li $v0, 8 与 fgets() 行为相同
li $a0, 1,不会有内容写入到内存中li $a0, 2,将会一次读取字母,一次读取换行符li $a0, 3,那么将一次性读取一个字母加换行符。因为只关心字母,下一读取时写入的内存地址只需+1,覆盖掉换行符- 字符读入—12
保存寄存器的值¶
除
$0,$gp,$sp外,对于认为不会发生改变的寄存器,如果我们在函数内中需要对其进行修改,则应在函数开始处进行一次入栈,函数结尾处进行一次出栈,遵循先入后出的规则。同时,$ra一定是第一个入栈的,$fp入栈前一定仅有$ra入栈。对于认为会发生改变的寄存器,如果在调用函数后仍然需要使用该寄存器内的值,则无论函数内部是否对其进行修改,都应该在调用函数前进行一次入栈,调用函数后进行一次出栈,遵循先入后出的规则。
其他常见错误¶
- 定义了
.data字段就必须有.text
MARS 查看运行指令数¶
Tools → Instruction Counter/Statistics → Connect to MIPS → 不用关闭窗口,直接运行即可
课上总结¶
T1 mooncake¶
分月饼 (想起离散课 lzj 的 ppt 了) , n 个人,月饼至少 l 个,至多 r 个,求带多少月饼实现每个人分得尽量多,且剩得尽量少,输出剩余月饼数。
思路:比较 l/n 和 r/n ,如果一样,剩余 l%n ;否则,剩得最少是 0
T2 prime¶
判断 [2, 2000] 内的某个整数是不是质数。
给了 C 代码:先判断所有数是质数还是合数,再输出要求的那个。 i 为质数,则 2i 3i 4i …为合数
T3 graph¶
有向图,找给定点能到达的出度为 0 的点的个数 (不含自身?)
挺有意思的题,也给了代码。上机的时候 jal dfs 完了后写了句 jr $ra ,自然是有问题。 jal dfs 相当于函数的调用, jr $ra 相当于 return 语句,注意什么时候写。
助教问答¶
怎么导出机器码; $a0 $t0 是什么类型寄存器;
nop 是什么?没答上来。就是空语句
Thoughts¶
这周写 C 代码的时候,自己是边写边思考 (以往是先打草稿) ,是 Paul 提到的那种感觉!
写第一题不在状态,没想好怎么写,就当跳跳虎,跳过了。感觉做不出来就大胆跳吧!先做能让自己静下来的题。看到前排的同学在自己研究 T3 的代码,沉着而冷静~