宏的使用

什么时候要用到宏?
在我们的汇编代码中,可能会出现很多需要停止程序运行的地方,我们可以使用如下代码:

li $v0,10
syscall
并把这段代码复制粘贴到许多地方。但是这样的代码多了,会导致代码过于冗长,复用性差,不利于阅读。

同学们在编写汇编程序时,尤其时有关矩阵的程序,可能会频繁地使用具有较高相似度的代码段,尤其是在通过行数和列数获取矩阵中的元素的时候,需要频繁地计算(行数*最大列数+列数)*4这样的数,代码如下(假设矩阵的最大列数为8,行数存在t0t0中,列数存在t0中,列数存在t1中,最终结果计算到$t2中):

sll t2,t2,t2,t0,3
add t2,t2,t2,t2,$t1
sll t2,t2,t2,t2,2
在编写程序的时候,我们可能会把这一小段代码复制多次并粘贴到不同的地方,对于矩阵乘法而言可能还要改一下寄存器的编号,稍微一个不注意就会产生难以发现的bug。因此,我们应当想办法杜绝这种问题的发生,提高代码的复用性。

宏(macro)就是用来解决这个问题的方案,我们可以使用宏来提高代码的复用性,让这种问题得以解决。

宏的用法
宏分为两种,不带参数的宏和带参数的宏。

不带参数的宏,定义的方式如下:

.macro macro_name

代码段

.end_macro
第一个例子适合用不带参数的宏解决,我们可以定义这样一个宏:

.macro done
li $v0,10
syscall
.end_macro
此时,在需要程序停止运行的地方,使用done语句,就可以让程序在那里退出。汇编器会把所有的macro_name语句替换成代码段;在第一个例子中,汇编器把所有的done语句替换成

li $v0,10
syscall
这样就实现了代码复用。

带参数的宏,定义的方式如下:

.macro macro_name(%parameter1, %parameter2, …)

代码段

.end_macro
和不带参数的宏不同的是,带参数的宏在macro_name后面有若干个用括号括起来的形式参数,每两个形式参数中间用逗号隔开,参数名前面有一个百分号。

第二个例子适合用带参数的宏解决,我们可以定义这样一个宏:

.macro getindex(%ans,%i,%j)
sll %ans,%i,3
add %ans,%ans,%j
sll %ans,%ans,2
.end_macro
其中%i代表行数,%j代表列数,%ans就是计算出来的结果((%i*8+%j)*4)。使用getindex(t2,t2,t2,t0,t1)t1)来调用这个宏,汇编器会用这段代码替换它,同时%ans被替换成t1)来调用这个宏,汇编器会用这段代码替换它,同时t2,%i被替换成t0t0,%j被替换成t0,t1,因此最终会被替换成

sll t2,t2,t2,t0,3
add t2,t2,t2,t2,$t1
sll t2,t2,t2,t2,2
在矩阵乘法中,只需要替换调用宏的语句,问题就会被轻松解决,同时代码的复用性得到了提高,代码也更容易被人读懂。

在汇编程序中,还有一种和C语言中#define类似的宏定义,一般用于常量的定义上,那就是.eqv。.eqv用法如下:

.eqv EQV_NAME string

汇编器会把所有EQV_NAME的地方替换成string,这可以用来定义一些常量。

在P8中,可能需要用汇编语言对数码管进行一些控制,控制数码管显示数字,每一个数字都有自己的编码,因此可以用.eqv对这些编码进行定义,例如:

.eqv TUBECHAR_0 0x7E
.eqv TUBECHAR_1 0x30
.eqv TUBECHAR_2 0x6D
使得代码更加清晰,并且避免了代码中出现各种意义不明的数字。

上一篇:机器学习(三):性能度量


下一篇:12_关于flask中的宏