5.4 KiB
5.4 KiB
实验六:宏调用
一、基础性实验
实验6_1 宏定义与调用一
实验目的
掌握宏的基本定义和调用方法,理解宏与子程序的区别。
实验内容
定义宏实现字符输出功能。
程序代码
DATAS SEGMENT
CHAR DB 'A'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
; 宏定义
; 功能:输出一个字符
; 参数:DL=字符
OUTPUT MACRO
MOV AH, 02H
INT 21H
ENDM
START:
MOV AX, DATAS
MOV DS, AX
MOV DL, CHAR
OUTPUT
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序分析
- 宏OUTPUT使用MACRO伪指令定义,以ENDM结束
- 宏调用时直接展开,参数通过DL传递
- 宏与子程序的区别:宏在调用处展开,子程序需要CALL调用
- 每次宏调用都会产生一段代码,适合代码量较少的情况
程序结果
运行后,屏幕显示字符'A'
实验6_2 宏定义与调用二
实验目的
掌握带参数的宏定义方法。
实验内容
定义宏实现数值显示功能。
程序代码
DATAS SEGMENT
NUM DB 5
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
; 宏定义
; 功能:显示数字0-9
; 参数:DL=数字
DISP_NUM MACRO
ADD DL, 30H ; 转换为ASCII码
MOV AH, 02H
INT 21H
ENDM
START:
MOV AX, DATAS
MOV DS, AX
MOV DL, NUM
DISP_NUM
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序分析
- 宏DISP_NUM带有参数DL
- 宏展开时,参数被替换到相应位置
- ADD DL,30H将数字转换为ASCII码
- 适合需要多次调用相同功能的情况
程序结果
运行后,屏幕显示数字'5'
二、加强性实验
实验6_3 宏嵌套调用
实验目的
掌握宏的嵌套调用,理解宏展开的机制。
实验内容
定义多个宏,实现复杂的输出功能。
程序代码
DATAS SEGMENT
MSG DB 'Test$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
; 宏定义:输出字符
PRINT_CHAR MACRO CHAR
MOV DL, CHAR
MOV AH, 02H
INT 21H
ENDM
; 宏定义:换行
NEWLINE MACRO
MOV DL, 0AH
MOV AH, 02H
INT 21H
MOV DL, 0DH
MOV AH, 02H
INT 21H
ENDM
; 宏定义:显示字符串
PRINT_STR MACRO STR
LEA DX, STR
MOV AH, 09H
INT 21H
ENDM
START:
MOV AX, DATAS
MOV DS, AX
PRINT_CHAR 'H'
PRINT_CHAR 'e'
PRINT_CHAR 'l'
PRINT_CHAR 'l'
PRINT_CHAR 'o'
NEWLINE
PRINT_STR MSG
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序分析
- 定义了三个宏:PRINT_CHAR、NEWLINE、PRINT_STR
- PRINT_CHAR接受参数CHAR,用于输出单个字符
- NEWLINE宏内部调用了两次INT 21H实现换行功能
- PRINT_STR宏使用LEA指令获取字符串地址
- 每次宏调用都会产生展开代码
程序结果
运行后,屏幕显示:
Hello
Test
实验6_4 宏与子程序比较
实验目的
理解宏与子程序的区别和各自适用场景。
实验内容
通过同一功能分别用宏和子程序实现,对比两者区别。
程序代码
DATAS SEGMENT
MSG1 DB 'Macro Test$'
MSG2 DB 'Subroutine Test$'
DATAS ENDS
STACKS SEGMENT
DB 64 DUP(?)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS, SS:STACKS
; 宏定义
PRINT_STRING MACRO STR
LEA DX, STR
MOV AH, 09H
INT 21H
ENDM
; 子程序定义
PRINT_PROC PROC
LEA DX, MSG2
MOV AH, 09H
INT 21H
RET
PRINT_PROC ENDP
START:
MOV AX, DATAS
MOV DS, AX
; 使用宏
PRINT_STRING MSG1
MOV DL, 0AH
MOV AH, 02H
INT 21H
; 使用子程序
CALL PRINT_PROC
MOV AH, 4CH
INT 21H
CODES ENDS
END START
程序分析
- 宏在调用处展开,节省调用开销,但代码膨胀
- 子程序代码独立存在,节省存储空间,但需要CALL/RET调用开销
- 宏适合代码量小、调用频繁的情况
- 子程序适合代码量大、调用次数少的情况
- 宏的参数传递通过文本替换实现,子程序通过寄存器或堆栈传递
程序结果
运行后,屏幕显示:
Macro Test
Subroutine Test
思考题
-
宏与子程序的主要区别是什么?
- 宏在调用处展开,代码膨胀;子程序独立存在,节省空间
- 宏不需要CALL/RET,节省调用开销;子程序需要调用开销
- 宏参数传递通过文本替换;子程序通过寄存器或堆栈传递
- 宏适合简短代码多次调用;子程序适合较长代码少次调用
-
宏定义的优点有哪些?
- 代码可读性好,程序结构清晰
- 参数传递灵活方便
- 无调用开销,执行效率高
- 便于程序的修改和维护
-
如何选择使用宏还是子程序?
- 代码量小、调用频繁:选择宏
- 代码量大、调用次数少:选择子程序
- 需要递归调用:必须使用子程序
- 需要节省存储空间:选择子程序
实验总结
- 宏使用MACRO伪指令定义,以ENDM结束
- 宏调用时直接展开,不占用运行时间
- 宏参数传递方便,适合少量代码的重复使用
- 宏会增加代码长度,但不占用存储空间(运行时)
- 子程序节省存储空间,但需要CALL/RET开销
- 选择宏还是子程序应根据代码量、调用次数和存储空间需求决定