Files
Operating-System/Experiment/asm-exp/实验六/实验六_宏调用.md
2026-06-25 00:09:09 +08:00

5.4 KiB
Raw Permalink Blame History

实验六:宏调用

一、基础性实验

实验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

程序分析

  1. 宏OUTPUT使用MACRO伪指令定义以ENDM结束
  2. 宏调用时直接展开参数通过DL传递
  3. 宏与子程序的区别宏在调用处展开子程序需要CALL调用
  4. 每次宏调用都会产生一段代码,适合代码量较少的情况

程序结果

运行后,屏幕显示字符'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

程序分析

  1. 宏DISP_NUM带有参数DL
  2. 宏展开时,参数被替换到相应位置
  3. ADD DL,30H将数字转换为ASCII码
  4. 适合需要多次调用相同功能的情况

程序结果

运行后,屏幕显示数字'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

程序分析

  1. 定义了三个宏PRINT_CHAR、NEWLINE、PRINT_STR
  2. PRINT_CHAR接受参数CHAR用于输出单个字符
  3. NEWLINE宏内部调用了两次INT 21H实现换行功能
  4. PRINT_STR宏使用LEA指令获取字符串地址
  5. 每次宏调用都会产生展开代码

程序结果

运行后,屏幕显示:

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

程序分析

  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. 选择宏还是子程序应根据代码量、调用次数和存储空间需求决定