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 的代码,沉着而冷静~