每个"宏"都要有一个名字,名字要写在"MACRO"伪指令前面。示例程序中定义的宏名字就是"PRINT"。如果需要在程序中使用某个宏之中的程序段,只要在程序需要的地方直接引用宏名即可。这就是为什么示例程序的MAIN过程里会有一个"PRINT"的原因了。
每个被调用的"宏"再编译的时候都要"展开",即用"宏"里面包含的程序段代替源程序中使用的宏名。比如给出的示例程序编译成COM文件之后与没有使用宏的程序完全一样:
C:\ASM\>DEBUG BESTWISH.COM[Enter] -U100 107[Enter] 0F8C:0100 BA0801 MOV DX,0108 0F8C:0103 B409 MOV AH,09 0F8C:0105 CD21 INT 21 0F8C:0107 C3 RET
通过这个示例程序,我们可以对"宏"汇编有个初步的认识:
① "宏"的定义与段、过程定义一样,具有特定的伪指令"MACRO"与"ENDM",格式上也类似于段定义与过程定义,只是"ENDM"的用法有些例外,它前面不能加上宏名;
② 宏的调用比较简单,只需要在源程序中直接引用宏名即可,不象子程序调用那样需要"CALL"指令;
③ 每个被调用的宏在编译的时候都要展开,如果源程序中多次调用了一个宏,那么编译生成的可执行文件里就会出现很多块结构相同的代码;
宏汇编的第三个特点可以说是宏与子程序最根本的区别,利用宏汇编虽然可以使源程序简化,但是却使编译之后的可执行文件变得冗长了。看来事物总是有利有弊的,宏虽然有优点,但是也不能滥用。
宏调用也可以象子过程调用那样传递参数,但是参数传递的方法与调用子过程完全不同。既不用寄存器,也不用存储器和堆栈。事实上宏调用更象高级语言中的函数调用。请看下面这个示例程序:
BESTWISH.ASM
print MACRO p1 ;定义一个带参数P1的宏 mov dx,offset p1 ;将参数P1的偏移地址送入DX寄存器 mov ah,09 ;利用DOS的09H功能输出一个字符串 int 21h ENDM ;宏结束 code segment assume cs:code,ds:code org 100h main proc near print msg ;输出字符串MSG ret msg db 'Best wish to you',0dh,0ah,24h main endp code ends end main
宏定义伪指令的完整用法是: 宏名 MACRO [参数1,参数2,......] ... (宏定义体) ENDM
参数可以有多个,都置于"MACRO"伪指令之后,组成参数表。调用宏的时候可以采用下面的方法传递参数:
宏名 [参数1,参数2,......]
注意定义了几个参数调用时就要传递几个,不能象一些高级语言调用函数那样可以省略几个,因为宏需要的参数没有默认值。