将程序分段、采用子程序或宏结构都是进行模块化程序设计本节介绍开发大型程序时采用的方法:
源程序文件的包含目标模块连接子程序库第十章 模块化程序设计把源程序分放在几个文本文件中,在汇编时通过包含伪指令 INCLUDE结合成一体
INCLUDE 文件名
可将常用的子程序形成,ASM汇编语言源文件
可将常用的宏定义存放在,MAC宏库文件中
可将常量定义、声明语句组织在,INC包含文件中例 4.21a
① 宏库文件 lt421a.mac
② 主程序文件 lt421a.asm
③ 子程序文件 sub421a.asm
10.1 源程序文件的包含
1
dispchar macro char ;显示 char字符
mov dl,char
mov ah,2
int 21h
endm
dispmsg macro message ;显示 message字符串
mov dx,offset message
mov ah,9
int 21h
endm
Lt421a.mac
include lt421a.mac
...
dispmsg msg1 ;提示输入数据
mov bx,offset buf
call input ;数据输入
cmp cx,0
je start4 ;没有输入数据则退出
mov count,cx
..,;显示输入的数据
..,;数据排序
..,;显示经排序后的数据
start4,.exit 0
include sub421a.asm
end
Lt421a.asm
子程序源文件有 3个子程序
ALdisp ;显示 2位 16进制数子程序(例 4.10)
sorting ;排序子程序(例 4.8)
input ;键盘输入子程序还包含一个宏
convert ;;将 DX两位 ASCII码转换为两位 16进制数
sub421a.asm
让我们重点分析键盘输入子程序 input;键盘输入子程序;入口参数,ds:bx=存放数据的缓冲区;出口参数,cx=数据个数
input proc
push ax
push dx
xor cx,cx ;数据个数清 0
input01,xor dx,dx ;输入字符清 0
input02,mov ah,1 ;键盘输入一个字符
int 21h
input之一继续,input之二
input10,cmp al,0dh
je input30;是 回车,结束整个数据的输入
cmp al,’ ’
je input20;是 空格和逗号,确认输入了一个数据
cmp al,’,’
je input20
cmp al,08h
je input17;是 退格,丢弃本次输入的数据,出错
input之二继续,input之三
cmp al,’0’ ;有效数字判断 (图 4.5b)
jb input17 ;小于 ’ 0’,不是有效数字,出错
cmp al,’f’
ja input17 ;大于 ’ f’,不是有效数字
cmp al,’a’
jb input11
sub al,20h ;’a’~ ’ f’转换成大写 ’ A’~ ’ F’
jmp input12
input11,cmp al,’F’
ja input17 ;字符小于 ’ a’、大于 ’ F’,出错
cmp al,’A’
jae input12 ;是 ’ A’~ ’ F’,有效字符
cmp al,’9’
ja input17 ;是 ’ 0’~ ’ 9’,有效字符
input之三继续,input之四
input12,cmp dl,0 ;有效字符的处理
jne input13
mov dl,al;dl=0,输入了一个数据的低位,则 dl←al
jmp input02 ;转到字符输入
input13,cmp dh,0
jne input17;dl≠0,dh≠0 输入 3位数据,出错
mov dh,dl;dl≠0,dh= 0输入了一个数据的高位
mov dl,al ;dh←dl,dl←al
jmp input02 ;转到字符输入
input之四继续,input之五
input17,mov dl,7 ;输入错误处理
mov ah,2
int 21h
mov dl,'?'
mov ah,2
int 21h
jmp input01 ;转到输入一个数据
input之五继续,input之六;转换正确的输入数据 (图 4.5c)
input20,convert
jmp input01 ;转到输入一个数据
input30,convert
pop dx
pop ax
ret ;返回,出口参数已设定
input endp
input之六继续,convert之一;;将 DX两位 ASCII码转换为两位 16进制数(图 4.5c)
convert macro
local input21,input22
local input24,input25
cmp dl,0;;dl=0,没有要转换的数据,退出
je input25
convert
之一继续,convert之二
cmp dl,'9'
jbe input21
sub dl,7 ;;字符 A~ F,则减 7
input21,and dl,0fh ;;转换低位
cmp dh,0 ;;dh=0,没有高位数据
je input24
cmp dh,'9'
jbe input22
sub dh,7
input22,shl dh,1
shl dh,1
shl dh,1
shl dh,1 ;;转换高位
or dl,dh ;;合并高、低位
convert
之二继续,convert之三源文件包含的操作步骤:
① 分别编辑生成各个文件
② 汇编、连接主程序文件
input24,mov [bx],dl ;;存入缓冲区
inc bx
inc cx ;;数据加 1
input25:
endm
convert
之三把常用子程序写成独立的源程序文件,单独汇编,
形成子程序的目标文件,OBJ
主程序也经过独立汇编之后形成目标文件连接程序将所有目标文件连接起来,最终产生可执行文件需要遵循的原则:
① 声明共用的变量、过程等
② 实现正确的段组合
③ 处理好参数传递问题
10.2 目标代码文件的连接
2
声明共用的变量、过程
各个模块间共用的变量、过程等要说明
PUBLIC 标识符 [,标识符,..];定义标识符的模块使用
EXTERN 标识符,类型 [,标识符,类型,..];调用标识符的模块使用
标识符是变量名、过程名等
类型是 byte / word / dword(变量)或 near / far(过程)
在一个源程序中,public/extern语句可以有多条
各模块间的 public/extern伪指令要互相配对,并且指明的类型互相一致实现正确的段组合
子程序文件必须定义在代码段中,也可以具有局部的数据变量
采用简化段定义格式,只要采用相同的存储模式,容易实现正确的近或远调用
完整段定义格式中,为了实现模块间的段内近调用( near类型),各自定义的段名、类别必须相同,组合类型都是
public。实际的程序开发中,各个模块往往由不同的程序员完成,不易实现段同名或类别相同,所以索性定义成远调用
( far类型)
定义数据段时,同样也要注意这个问题。当各个模块的数据段不同时,要正确设置数据段 DS寄存器的段基地址处理好参数传递问题
少量参数可用寄存器或堆栈直接传送数据本身
大量数据可以安排在缓冲区,用寄存器或堆栈传送数据的存储地址
还可利用变量传递参数,但是要采用
public/extern声明为公共(全局)变量
这些也是子程序间的参数传递方法例 4.21b
主程序 lt421b.asm并入宏定义
子程序文件 sub421b.asm,要加上段定义语句、声明语句等,但不需要起始点和结束点模块连接的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 连接各个目标文件,形成可执行文件把常用子程序写成独立的源文件,单独汇编形成 OBJ文件后,存入 子程序库主程序也单独汇编形成 OBJ文件主程序连接时,调入子程序库中的子程序模块,产生最终的可执行文件例
① 主程序文件 lt421c.asm
② 子程序文件 sub421c1.asm
③ 子程序文件 sub421c2.asm
④ 子程序文件 sub421c3.asm
10.3 子程序库的调入
3
..,;宏定义
.code
extern ALdisp:near,sorting:near,input:near;声明其他模块中的子程序
.startup
...
.exit 0
end
Lt421c.asm
.model small
.code
public aldisp
Aldisp proc
...
Aldisp endp
end
sub421c1.
asm
.model small
.code
public sorting
sorting proc
...
sorting endp
end
sub421c2.
asm
.model small
.code
public input
input proc
...
input endp
end
sub421c3.
asm
库文件调入的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 用库管理文件,将子程序模块添加到库文件(,LIB)中
④ 连接主程序,提供库文件,
形成可执行文件补充例题
将子程序补充例题 1~ 3的子程序编写成模块,供主程序调用
实现功能:从键盘输入有符号 10进制数,求它们的平均值,然后输出
源程序文件进行简单修改
– 主程序文件
– 子程序文件
利用目标代码文件的连接形成可执行文件第一章 基础知识汇编语言和 C语言 编程
C/C++语言是一个被广泛使用的程序设计语言,它不仅具有良好的高级语言特征,而且还具有一些低级语言的特点,如:寄存器变量、位操作等。所以,C语言的程序与汇编语言程序之间能很平滑地衔接。另外,目前主要的 C语言程序开发环境,如,Turbo C/C++、
Borland C/C++等,也都提供了很好的混合编程手段。
一、汇编指令的嵌入为了提高 C语言程序内某特殊功能段的处理效率,我们可以在其源程序中嵌入一段汇编语言程序段。这样做,虽然能达到提高了程序处理效率的目的,但它无疑以丧失源程序的可移植性为代价。所以,当想用 C语言和汇编语言混合编程时,程序员需要权衡采用这种方法的利与弊。
在 C语言中,嵌入汇编语言的语法如下 (*):
asm <opcode> <operands> <; or newline>
注意:这里的分号 ';'不是汇编语言中起注释作用的分号,而是作为语句的分隔符。
若 C语言源程序中嵌入一条汇编语句,则可按下列方式来做:
asm mov ax,data
若要嵌入一组汇编语句,则需要用括号 '{'和 '}'把它们括起来。
asm {mov ax,data1
xchg ax,data2mov data1,ax //实现整型变量 data1和 data2之值的交换
}
第一章 基础知识汇编语言和 C语言 编程例 在 C语言源程序中嵌入汇编语言语句实现赋值语句 A=A+B+C,其中,A、
B,C都是整型变量。
解,……
asm
{push ax //实现整型变量 A=A+B+C
mov ax,A
add ax,B
add ax,C
mov A,ax
pop ax
}
二,C语言程序的汇编输出
源程序文件的包含目标模块连接子程序库第十章 模块化程序设计把源程序分放在几个文本文件中,在汇编时通过包含伪指令 INCLUDE结合成一体
INCLUDE 文件名
可将常用的子程序形成,ASM汇编语言源文件
可将常用的宏定义存放在,MAC宏库文件中
可将常量定义、声明语句组织在,INC包含文件中例 4.21a
① 宏库文件 lt421a.mac
② 主程序文件 lt421a.asm
③ 子程序文件 sub421a.asm
10.1 源程序文件的包含
1
dispchar macro char ;显示 char字符
mov dl,char
mov ah,2
int 21h
endm
dispmsg macro message ;显示 message字符串
mov dx,offset message
mov ah,9
int 21h
endm
Lt421a.mac
include lt421a.mac
...
dispmsg msg1 ;提示输入数据
mov bx,offset buf
call input ;数据输入
cmp cx,0
je start4 ;没有输入数据则退出
mov count,cx
..,;显示输入的数据
..,;数据排序
..,;显示经排序后的数据
start4,.exit 0
include sub421a.asm
end
Lt421a.asm
子程序源文件有 3个子程序
ALdisp ;显示 2位 16进制数子程序(例 4.10)
sorting ;排序子程序(例 4.8)
input ;键盘输入子程序还包含一个宏
convert ;;将 DX两位 ASCII码转换为两位 16进制数
sub421a.asm
让我们重点分析键盘输入子程序 input;键盘输入子程序;入口参数,ds:bx=存放数据的缓冲区;出口参数,cx=数据个数
input proc
push ax
push dx
xor cx,cx ;数据个数清 0
input01,xor dx,dx ;输入字符清 0
input02,mov ah,1 ;键盘输入一个字符
int 21h
input之一继续,input之二
input10,cmp al,0dh
je input30;是 回车,结束整个数据的输入
cmp al,’ ’
je input20;是 空格和逗号,确认输入了一个数据
cmp al,’,’
je input20
cmp al,08h
je input17;是 退格,丢弃本次输入的数据,出错
input之二继续,input之三
cmp al,’0’ ;有效数字判断 (图 4.5b)
jb input17 ;小于 ’ 0’,不是有效数字,出错
cmp al,’f’
ja input17 ;大于 ’ f’,不是有效数字
cmp al,’a’
jb input11
sub al,20h ;’a’~ ’ f’转换成大写 ’ A’~ ’ F’
jmp input12
input11,cmp al,’F’
ja input17 ;字符小于 ’ a’、大于 ’ F’,出错
cmp al,’A’
jae input12 ;是 ’ A’~ ’ F’,有效字符
cmp al,’9’
ja input17 ;是 ’ 0’~ ’ 9’,有效字符
input之三继续,input之四
input12,cmp dl,0 ;有效字符的处理
jne input13
mov dl,al;dl=0,输入了一个数据的低位,则 dl←al
jmp input02 ;转到字符输入
input13,cmp dh,0
jne input17;dl≠0,dh≠0 输入 3位数据,出错
mov dh,dl;dl≠0,dh= 0输入了一个数据的高位
mov dl,al ;dh←dl,dl←al
jmp input02 ;转到字符输入
input之四继续,input之五
input17,mov dl,7 ;输入错误处理
mov ah,2
int 21h
mov dl,'?'
mov ah,2
int 21h
jmp input01 ;转到输入一个数据
input之五继续,input之六;转换正确的输入数据 (图 4.5c)
input20,convert
jmp input01 ;转到输入一个数据
input30,convert
pop dx
pop ax
ret ;返回,出口参数已设定
input endp
input之六继续,convert之一;;将 DX两位 ASCII码转换为两位 16进制数(图 4.5c)
convert macro
local input21,input22
local input24,input25
cmp dl,0;;dl=0,没有要转换的数据,退出
je input25
convert
之一继续,convert之二
cmp dl,'9'
jbe input21
sub dl,7 ;;字符 A~ F,则减 7
input21,and dl,0fh ;;转换低位
cmp dh,0 ;;dh=0,没有高位数据
je input24
cmp dh,'9'
jbe input22
sub dh,7
input22,shl dh,1
shl dh,1
shl dh,1
shl dh,1 ;;转换高位
or dl,dh ;;合并高、低位
convert
之二继续,convert之三源文件包含的操作步骤:
① 分别编辑生成各个文件
② 汇编、连接主程序文件
input24,mov [bx],dl ;;存入缓冲区
inc bx
inc cx ;;数据加 1
input25:
endm
convert
之三把常用子程序写成独立的源程序文件,单独汇编,
形成子程序的目标文件,OBJ
主程序也经过独立汇编之后形成目标文件连接程序将所有目标文件连接起来,最终产生可执行文件需要遵循的原则:
① 声明共用的变量、过程等
② 实现正确的段组合
③ 处理好参数传递问题
10.2 目标代码文件的连接
2
声明共用的变量、过程
各个模块间共用的变量、过程等要说明
PUBLIC 标识符 [,标识符,..];定义标识符的模块使用
EXTERN 标识符,类型 [,标识符,类型,..];调用标识符的模块使用
标识符是变量名、过程名等
类型是 byte / word / dword(变量)或 near / far(过程)
在一个源程序中,public/extern语句可以有多条
各模块间的 public/extern伪指令要互相配对,并且指明的类型互相一致实现正确的段组合
子程序文件必须定义在代码段中,也可以具有局部的数据变量
采用简化段定义格式,只要采用相同的存储模式,容易实现正确的近或远调用
完整段定义格式中,为了实现模块间的段内近调用( near类型),各自定义的段名、类别必须相同,组合类型都是
public。实际的程序开发中,各个模块往往由不同的程序员完成,不易实现段同名或类别相同,所以索性定义成远调用
( far类型)
定义数据段时,同样也要注意这个问题。当各个模块的数据段不同时,要正确设置数据段 DS寄存器的段基地址处理好参数传递问题
少量参数可用寄存器或堆栈直接传送数据本身
大量数据可以安排在缓冲区,用寄存器或堆栈传送数据的存储地址
还可利用变量传递参数,但是要采用
public/extern声明为公共(全局)变量
这些也是子程序间的参数传递方法例 4.21b
主程序 lt421b.asm并入宏定义
子程序文件 sub421b.asm,要加上段定义语句、声明语句等,但不需要起始点和结束点模块连接的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 连接各个目标文件,形成可执行文件把常用子程序写成独立的源文件,单独汇编形成 OBJ文件后,存入 子程序库主程序也单独汇编形成 OBJ文件主程序连接时,调入子程序库中的子程序模块,产生最终的可执行文件例
① 主程序文件 lt421c.asm
② 子程序文件 sub421c1.asm
③ 子程序文件 sub421c2.asm
④ 子程序文件 sub421c3.asm
10.3 子程序库的调入
3
..,;宏定义
.code
extern ALdisp:near,sorting:near,input:near;声明其他模块中的子程序
.startup
...
.exit 0
end
Lt421c.asm
.model small
.code
public aldisp
Aldisp proc
...
Aldisp endp
end
sub421c1.
asm
.model small
.code
public sorting
sorting proc
...
sorting endp
end
sub421c2.
asm
.model small
.code
public input
input proc
...
input endp
end
sub421c3.
asm
库文件调入的操作步骤:
① 分别编辑生成各个文件
② 分别汇编各个文件
③ 用库管理文件,将子程序模块添加到库文件(,LIB)中
④ 连接主程序,提供库文件,
形成可执行文件补充例题
将子程序补充例题 1~ 3的子程序编写成模块,供主程序调用
实现功能:从键盘输入有符号 10进制数,求它们的平均值,然后输出
源程序文件进行简单修改
– 主程序文件
– 子程序文件
利用目标代码文件的连接形成可执行文件第一章 基础知识汇编语言和 C语言 编程
C/C++语言是一个被广泛使用的程序设计语言,它不仅具有良好的高级语言特征,而且还具有一些低级语言的特点,如:寄存器变量、位操作等。所以,C语言的程序与汇编语言程序之间能很平滑地衔接。另外,目前主要的 C语言程序开发环境,如,Turbo C/C++、
Borland C/C++等,也都提供了很好的混合编程手段。
一、汇编指令的嵌入为了提高 C语言程序内某特殊功能段的处理效率,我们可以在其源程序中嵌入一段汇编语言程序段。这样做,虽然能达到提高了程序处理效率的目的,但它无疑以丧失源程序的可移植性为代价。所以,当想用 C语言和汇编语言混合编程时,程序员需要权衡采用这种方法的利与弊。
在 C语言中,嵌入汇编语言的语法如下 (*):
asm <opcode> <operands> <; or newline>
注意:这里的分号 ';'不是汇编语言中起注释作用的分号,而是作为语句的分隔符。
若 C语言源程序中嵌入一条汇编语句,则可按下列方式来做:
asm mov ax,data
若要嵌入一组汇编语句,则需要用括号 '{'和 '}'把它们括起来。
asm {mov ax,data1
xchg ax,data2mov data1,ax //实现整型变量 data1和 data2之值的交换
}
第一章 基础知识汇编语言和 C语言 编程例 在 C语言源程序中嵌入汇编语言语句实现赋值语句 A=A+B+C,其中,A、
B,C都是整型变量。
解,……
asm
{push ax //实现整型变量 A=A+B+C
mov ax,A
add ax,B
add ax,C
mov A,ax
pop ax
}
二,C语言程序的汇编输出