?? 匯009.txt
字號:
方法1:使用條件匯編偽指令IF
INPUT MACRO
IF DOS ;當符號DOS不為0時,則使用DOS的功能調用
MOV AH, 1H
INT 21H
ELSE ;否則,將使用BIOS的功能調用
MOV AH, 10H
INT 16H
ENDIF
ENDM
在引用宏INPUT時,匯編程序會根據DOS是否為0來生成調用不同輸入功能的程序段。
方法2:使用條件匯編偽指令IFDEF
INPUT MACRO
IFDEF DOS ;當定義了DOS,則使用DOS的功能調用
MOV AH, 1H
INT 21H
ELSE ;否則,將使用BIOS的功能調用
MOV AH, 10H
INT 16H
ENDIF
ENDM
在引用宏INPUT時,匯編程序會根據符號DOS是否已定義來生成調用不同輸入功能的程序段。
例9.15 編寫一個可用功能調用輸入字符的宏定義。
解:
READCH MACRO char
MOV AH, 1H
INT 21H ;接受一個字符,并存入AL中
IFNB <char> ;若參數char有實參與之對應
IFDIF <char>, <AL> ;若參數char≠AL,則把所輸入字符保存到實參中
MOV char, AL
ENDIF
ENDIF
ENDM
9.6 宏的擴充
MASM 6.11編程系統對宏定義及其相關語句進行了一定程度的擴充。雖然這些擴充給編程帶來了一些方便,但它們不一定能被其它的匯編語言編程系統所接受,所以,程序員在使用這些方便的擴充功能時,要注意到可能帶來的限制。
下面介紹MASM 6.11編程系統對宏及其相關語句的擴充。
9.6.1 宏定義形式
在MASM 6.11編程系統中,其宏定義的一般形式如下:
宏名
MACRO [參數1[:tag]] [,參數2[:tag]...]
[LOCAL varlist]
…
[EXITM [value]]
ENDM ;宏定義體內的局部變量和標號
;宏的定義體
對上述宏定義的說明與9.1.1節中的說明完全一致,其需要增加的說明如下:
tag—— 其值可以是REQ、=<缺省值>或VARARG
REQ 指定該參數是不可缺少。在宏引用時,若該參數不對應某個“實參”,那么,匯編程序會報錯;
=<缺省值> 在宏引用時,若不指定該參數所對應的“實參”,那么,該參數就取其缺省值;
VARARG 該參數對應一個可變長的實參表,各實參之間用逗號分開;若參數的屬性指定為VARARG,那么,該參數一定要是最后一個參數。
有關該屬性的應用,請見隨后9.6.7節中的舉例。
value—— 宏功能的返回值,其為可選項。
9.6.2 重復偽指令REPEAT
重復偽指令REPEAT與前面9.4.1節中偽指令REPT在功能和使用方式方面完全一致,設置該偽指令的主要原因是保證與先前版本的兼容性。
偽指令REPEAT的使用方式如下:
REPEAT
數值表達式
語句序列 ;被重復的匯編語言語句
ENDM
9.6.3 循環偽指令WHILE
循環偽指令WHILE的使用方式如下:
WHILE
Exp
語句序列 ;被重復的匯編語言語句
ENDM
其功能是先判斷表達式Exp是否為假(或為0),若是,則終止該偽指令的功能,否則,循環匯編下面的指令塊。表達式Exp是能在匯編時計算出其值的數值表達式。
例9.16:編寫一個帶有參數result和k的宏,其功能是把1+2+…+k的累加和存入result之中,其中:result是不可缺省的,k的缺省值為1。
解:
SUM
MACRO result:REQ, k:=<1>
LOCAL n
n = k
mov result, 0
WHILE n
add result, n
n = n - 1
ENDM
ENDM
有了上面的宏定義,就可書寫下面的宏引用來實現其相應的功能:
SUM ax, 10 ;寄存器ax=1+2+3+…+10
SUM bh ;寄存器bh=1,因為第二個形參取其缺省值
SUM ecx, 100 ;寄存器ecx=1+2+3+…+100
SUM data, 20 ;存儲單元data=1+2+3+…+20
9.6.4 循環偽指令FOR
循環偽指令FOR與9.4.2節中偽指令IRP在功能上完全一致,設置該偽指令的原因也是為了保證與先前版本的兼容性。
偽指令FOR的使用方式如下:
FOR
parameter[:REQ|:=<default>], <argument [, argument]...>
語句序列 ;被重復的匯編語言語句
ENDM
其中各參數的說明如下:
parameter
一個合法的標識符,它依次取后面參數表中的值。在指令序列中,該變量的每次出現都用其值所替換;
:REQ 說明該變量的取值不能為空;
:=<default> 指定該變量的缺省值,若后面的參數表缺省某個參數(用連續的逗號),這時,該循環變量將取其缺省值;
Argument 參數表中可含有文本、符號、字符串或數值常量,每個參數之間要用逗號分割。
例如:
FOR
data:=<?>, <"123", , 21, 0>
DB data
ENDM
……
FOR
reg:REQ, <ax, bx, dx>
push reg
ENDM
該語句在宏展開時,將得到下列語句:
DB "123"
DB ?
DB 21
DB 0
……
push ax
push bx
push dx
9.6.5 循環偽指令FORC
循環偽指令FOR與9.4.3節中偽指令IRPC在功能上完全一致,它也是為保證與先前版本的兼容性而設置的。
偽指令FORC的使用方式如下:
FORC
parameter, <string>
語句序列 ;被重復的匯編語言語句
ENDM
其中各參數的說明如下:
parameter: 一個合法的標識符,它依次取字符串中的每個字符。在語句序列中,該變量的每次出現都用其值所替換;
String: 一個字符串或被定義為字符串的符號名,字符串中的空格也被算為一個字符。括號"<"、">"是必不可少的。
例如:
FORC
data, <1?3>
DB data
ENDM
……
FORC
reg, <abd>
push reg&x
ENDM
該語句在宏展開時,將得到下列語句:
DB 1
DB ?
DB 3
……
push ax
push bx
push dx
9.6.6 轉移偽指令GOTO
轉移偽指令GOTO用于實現宏定義體內的轉移功能,其使用方式如下:
GOTO 標號
…
:標號 ;標號后不能寫指令,但可寫注釋
…
該偽指令的功能是使匯編程序轉移到“標號”處匯編,它只能在宏定義MACRO、REPEAT、WHILE、FOR和FORC等語句塊內使用,該標號也只在該語句塊內有效。
9.6.7 宏擴充的舉例
例9.17:編寫一個給任意寄存器或存儲單元清零的宏定義。
解:
Clear
list : VARARG
FOR data:REQ, <list>
mov data, 0
ENDM
ENDM
有了上面的宏定義,下面的二個宏引用都是正確的,盡管宏引用時所帶的參數個數是不同的。這正是參數屬性VARARG的作用所在。
Clear ax, bx
……
Clear si, cl, MemVar, edx ;MemVar是內存變量,任意類型都可以
這二個宏引用展開時所得到的指令如下:
mov ax, 0
mov bx, 0
……
mov si, 0
mov cl, 0
mov MemVar, 0
mov edx, 0
9.6.8 系統定義的宏
MASM 6.11系統定義了大量的標準宏,程序員能很方便地使用它們。在使用這些系統宏之前,要象C語言那樣用偽指令INCLUDE把有關“宏庫”文件包含在用戶的源程序中。主要的系統宏庫文件有:DOS.INC和BIOS.INC,它們存放在系統的include子目錄中。
例9.18:使用系統宏定義,編寫從鍵盤上讀取一個字符。
解:
include dos.inc ;把系統宏定義文件包含在源程序之中
……
@getchar 1, 1 ;引用系統宏定義
……
下面是系統宏@getchar的使用參數描述和定義,其它系統宏的有關信息請參閱相關的宏定義文件。
1、系統宏@GetChar的使用說明
宏的功能: 從鍵盤讀字符
使用語法: @GetChar [echo] [,[break] [,clearbuf]]
參數說明: <echo> ;常量,非零表示“回顯”,缺省值為“回顯”
<break> ;常量,非零表示接受“^C”,缺省值為“接受”
<clearbuf> ;常量,非零表示清鍵盤緩沖區,缺省值為“不清”
返回參數: AL=ASCII碼
內容破壞: AX,DL(若回顯,且不接受^C)
參見內容: INT 21h — 01h、07h、08h和0Ch,@GetStr
2、系統宏@GetChar的定義
該宏定義在宏庫文件dos.inc中,其具體宏定義如下:
@GetChar
MACRO ech:=<1>, cc:=<1>, clear:=<0>
LOCAL funct, disp
disp = 1
IF ech
IF cc
funct = 01h ;使用功能1
ELSE
funct = 07h ;使用功能7
disp = 02h ;設置需要回顯標志
ENDIF
ELSE
IF cc
funct = 08h ;使用功能8
ELSE
funct = 07h ;使用功能7
ENDIF
ENDIF
IFE clear
mov ah, funct ;置功能號
ELSE
mov ah, 0Ch ;先清輸入緩沖區,再接受鍵盤輸入
mov al, funct
ENDIF
Int 21h ;調用DOS功能中斷
IF disp EQ 02h ;檢查是否需要回顯
mov dl, al
mov ah, 02h
int 21h
ENDIF
ENDM
對于上面的宏定義,程序員完全可以把它修改成其它形式的宏定義。
9.7 習題
9.1、在宏定義時,使用的關鍵字是什么?宏名是否需要成對出現?
9.2、在宏引用時,是否要求實參與形參的個數相等?若不要求,請簡述當二者個數不一致時,會出現什么情況。
9.3、宏和子程序的主要區別有哪些?一般在什么情況下選用宏較好,在什么情況下選用子程序較好?
9.4、宏的參數如何傳入宏定義體的?宏的參數傳遞與子程序的參數傳遞有哪些區別?
9.5、在有標號的宏定義體中,為什么最好使用LOCAL偽指令來說明標號?它在宏定義體中應處于什么位置?
9.6、子程序和宏中的LOCAL偽指令的作用有哪些不同?
9.7、編寫32位相加的宏ADD32,它把32位寄存器組BX-AX加到DX-CX中。
9.8、編寫符號擴展的宏CBD,它將存于AL中的有符號數擴展成ECX-EBX中64位有符號數(其中:ECX是64位有符號數的高位)。
9.9、編寫字母大小寫互換的宏Exchange,其有一個形參,允許字節型的寄存器或存儲單元作為實參來引用。
9.10、編寫一個宏AddList Para1, Para2, num,其功能是將從Para2開始的內存單元的值加到以Para1開始的內存單元中,num是相加的字節數。
9.11、編寫一個宏SUM Data, Length, Result,其功能是求從Data開始的字節累加和,并把結果存入字類型參數Result中,Length是需要累加的字節數。
9.12、編寫一個宏來定義26個大寫字母表。
9.13、編寫一個宏,它產生n條NOP指令,其中n是宏的形式參數。
9.14、INCLUDE指示符的作用是什么?
9.15、編寫只有一個形式參數的宏PRINT,其具體功能如下:
1)、若引用時帶有參數,則在屏幕上顯示其參數字符,如:PRINT 'A',則顯示字符'A';
2)、若引用時不帶實參,則顯示回車和換行,如:PRINT。
提示:用IFB或IFNB語句來測試是否有參數。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -