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