目录
一,定义和引用
宏是用来代表一个具有特定功能的程序段,它只需在源程序中定义一次
1,定义
在使用宏之前必须先定义宏,
格式:
宏名 macro [形参1, 形参2,……]
……
endm
规定:
MACRO和ENDM是二个必须成对出现的关键字,它们分别表示宏定义的开始和结束; | |
MACRO和ENDM之间的部分是宏的定义体,它是由指令、伪指令或引用其它宏所组成的程序片段,是宏所包含的具体内容; | |
“宏名”是由程序员指定的一个合法的标识符,它代表该宏; | |
宏名可以与指令助忆符、伪指令名相同。在这种情况下,宏指令优先,而同名的指令或伪指令都失效; | |
在ENDM的前面不要再写一次宏名,这与段或子程序定义的结束方式有所不同; | |
在宏定义的首部可以列举若干个形式参数,每个参数之间要用逗号分隔 |
2,引用
在源程序中,一旦定义了宏,那么,在该程序的任何位置都可以直接引用宏,而不必重复编写相应的程序段。
格式:
宏名 [实参1, 实参2, ……]
其中:实参的位置要与形参的位置对应,但实参的个数可以与形参的个数不相等。
3,参数传递方式
在引用宏时,参数是通过“实参”替换“形参”的方式来实现传递的。
参数的形式灵活多样,参数可以是常熟、寄存器、存储单元和表达式,还可以是指令的操作码。
4,宏的嵌套定义
宏的嵌套定义有两种方式:宏定义内引用其他的宏和宏定义体内其他的宏。
1)宏定义体内引用其他的宏
在宏的定义体中又引用了其它已定义好的宏,这种宏定义方式在实际的编程过程时常会用到。如果被引用的宏还没定义的话,汇编程序将会显示出错信息。
这种定义方式虽然有其好的一面,但他使宏的定义更加隐藏,削弱了程序的可读性,降低了程序的可维护性,因此,这种宏定义方式在实际的编程中很少使用。
5,宏与子程序的区别
宏和子程序都是为了简化源程序的编写,提高程序的可维护性,但是它们二者之间存在着以下本质的区别:
1、在源程序中,通过书写宏名来引用宏,而子程序是通过CALL指令来调用; | |
2、汇编程序对宏通过宏扩展来加入其定义体,宏引用多少次,就相应扩展多少次,所以,引用宏不会缩短目标程序;而子程序代码在目标程序中只出现一次,调用子程序是执行同一程序段,因此,目标程序也得到相应的简化; | |
3、宏引用时,参数是通过“实参”替换“形参”的方式来实现传递的,参数形式灵活多样,而子程序调用时,参数是通过寄存器、堆栈或约定存储单元进行传递的; | |
4、宏引用语句扩展后,目标程序中就不再有宏引用语句,运行时,不会有额外的时间开销,而子程序的调用在目标程序中仍存在,子程序的调用和返回均需要时间。 |
总之,当程序片段不长,速度是关键因素时,可采用宏来简化源程序,但当程序片段较长,存储空间是关键因素时,可采用子程序的方法来简化源程序和目标程序。
二,宏参数的特殊运算符
1,在宏定义中,如果形式参数与其他字符连接在一起,或形式参数出现在字符串之中,那么,就必须使用连接运算符(&)。
2,字符串整体传递运算符
字符串整体传递运算符是一对尖括号<>,用他括起来的内容将作为一个字符串进行形式参数的整体替换。
在宏引用时,如果实参内包含逗号、空格等间隔符,则必须使用该操作符,以保证实参的完整性。如果实参是某个具有特殊含义的字符,为了使它只表示该字符本身,也需要用该运算符括起来。
3,字符转义运算符
在引用宏时,如果实参中含有特殊字符,而又要该特殊字符当作普通体服来出来,那么,就必须在该特殊字符前加上字符转义运算符“!”
4,计算表达式运算符
在引用宏时,使用计算表达式运算符“%”表示把后面表达式的结果当作实参进行替换,而不是该表达式的整个式子。
三,与宏有关的伪指令
1,局部标号伪指令local
在宏定义中,如果存在标号,则该标号要用伪指令local说明为局部标号,否则,当在源程序中,有多余一次引用该宏时,汇编程序在进行宏扩展后将会给出:标号重复定义的错误。
伪指令local的一般格式:
local 标号1, 标号2 ……
伪指令local必须时伪指令macro后的第一条语句,并且在macro和local之间也不允许有注释和分号标志。
2,取消宏定义伪指令
伪指令 purge
格式:
purge 宏名1, 宏名2, ……
该伪指令通知汇编程序取消“宏名1, 宏名2, ……”宏名表中的宏定义。
在此语句后,如果还有这些宏的引用语句,则汇编程序不会把他们当作宏来扩展,并且会报错。
伪指令purge 使用频率很低。
3,终止宏扩展伪指令
伪指令 exitm
格式:
exitm
该伪指令书写在宏定义体中,用来告诉汇编程序:如果遇到该伪指令,那么,立即中止对该伪指令之下语句的扩展。如果在嵌套的内层宏中遇到了该伪指令,则退出到宏嵌套的外层。
在一般情况下,伪指令EXITM与条件伪指令一起使用,以便在不同的条件下挑选出不同的语句。
伪指令EXITM的使用频率也很低。
四,重复汇编伪指令
在编写源程序时,有时会出现连续相同或相似的语句(组)。当出现这种情况时,可利用重复伪指令来重复语句,从而达到简化程序的目的。
重复汇编伪指令所定义的重复块是宏的一种特殊形式,也是由伪指令ENDM来结束重复块。用重复汇编伪指令定义的重复块也可带有参数,并在汇编过程中参数被实参代替,但重复块不会被命名,不能在程序的其它地方引用。
1,rept
作用:把一组语句重复指定的次数,该重复次数由伪指令后面的数值表达式来确定。
格式:
rept 数值表达式
重复的语句组
endm
2,伪指令irp
伪指令IRP的作用是用每个参数创建一组语句,其重复次数由伪指令后面参数表中参数的个数来确定。
格式:
irp 形式参数, <实参1, 实参2, …… ,实参n>
重复的语句组
endm
3,伪指令irpc
伪指令iprc的作用与irp相似,其实参表是一个字符串,并对字符串中的每个字符创建一组语句,所以,其重复次数是由该字符串中的字符数来确定。
格式:
irpc 形式参数, 字符串
重复的语句组
endm
五,条件汇编伪指令
条件汇编伪指令是告诉汇编程序:根据某种条件确定一组程序段是否加入到目标程序中。使用条件汇编伪指令的主要目的是:同一个源程序能根据不同的汇编条件生成不同功能的目标程序,增强宏定义的使用范围。
条件汇编伪指令与高级语言(如:C/C++)的条件编译语句在书写形式上相似,在所起作用方面是完全一致的。
1,功能
格式:
if nnnn 条件表达式
语句组1
[else
语句组2]
endif
2,举例
六,宏的扩充
MASM 6.11编程系统对宏定义及其相关语句进行了一定程度的扩充。虽然这些扩充给编程带来了一些方便,但它们不一定能被其它的汇编语言编程系统所接受,所以,程序员在使用这些方便的扩充功能时,要注意到可能带来的限制。
1,宏定义形式
2,重复伪指令repeat
3,循环伪指令while
4,循环伪指令for
5,循环伪指令forc
6,转移伪指令goto
7,宏扩充的举例
8,系统定义的宏