汇编语言之应用程序的设计说明.docx
- 文档编号:7448810
- 上传时间:2023-01-24
- 格式:DOCX
- 页数:31
- 大小:33.31KB
汇编语言之应用程序的设计说明.docx
《汇编语言之应用程序的设计说明.docx》由会员分享,可在线阅读,更多相关《汇编语言之应用程序的设计说明.docx(31页珍藏版)》请在冰豆网上搜索。
汇编语言之应用程序的设计说明
第10章应用程序的设计
在前面各章节中,我们侧重介绍了汇编语言程序设计中各组成部分的作用,本章的重点是对前面所学知识的综合运用。
希望通过各种不同类型的例子,使读者能够掌握用汇编语言编程的基本技巧。
10.1字符串的处理程序
字符或字符串是一类重要的非数值计算的处理对象。
许多编辑软件都具有字符串查找、替换、大小写的转换、单词的自动识别等功能,网络上的信息搜索也是现在一种常用的功能等,这些功能的实现无疑都要涉及到字符串的处理功能。
为了方便对字符串的处理,各种常用的编程环境也都给予了足够的支持。
如:
C语言编程环境提供了大量处理字符串的标准函数,象strlen、strcmp和strcpy等函数;C++、VC或VB等编程环境提供了字符串类String等。
这些函数或类大大方便了程序员的编程。
在计算机系统,为了加快字符串的处理,在其指令系统中设置了多条处理字符串的指令,其详细容请参阅第5.2.11节中的介绍。
下面我们将通过几个例子来学习汇编语言处理字符串的方法。
例10.1编写一个求字符串长度的子程序Strlen,要求字符串的首地址为入口参数,且以ASCII码0为结束符,CX为出口参数,其存放该字符串的长度。
解:
.MODEL SMALL,C
.DATA
buff
DB "Thisisaexample.",0
.CODE
Strlen
PROC USESAXBX,String:
PTRBYTE
MOV
BX,String
XOR
CX,CX
MOV
AL,[BX]
.WHILE AL!
=0
INC
CX
INC
BX
MOV
AL,[BX]
.ENDW
RET
Strlen
ENDP
.STARTUP
INVOKE Strlen,ADDRbuff
.EXIT 0
END
例10.2编写一个把字符串中的所有小写字符转换成大写字符的子程序Strupr,要求字符串的首地址和结束符为其入口参数。
解:
.MODEL SMALL,C
.DATA
buff
DB "Thisisaexample.",0
.CODE
Strupr
PROC USESAXBX,String:
PTRBYTE,Tail:
BYTE
MOV
BX,String
.REPEAT
MOV
AL,[BX]
.IF AL>='a'&&AL<='z'
SUB
AL,20H
MOV
[BX],AL
.ENDIF
INC
BX
.UNTIL
AL==Tail
RET
Strupr
ENDP
.STARTUP
INVOKE Strupr,ADDRbuff,0
.EXIT 0
END
例10.3编写一个从字符串中拷贝子串的子程序Strncpy,它有四个参数str1、str2、idx和num,其具体功能为把字符串str2中从第idx个(从0开始记数)字符开始、num个字符传送给str1,字符串str1和str2都是以ASCII码0为结束符。
解:
.MODEL
SMALL,C
.DATA
str1
DB "12345ABCDEF",0
str2
DB 20DUP('A')
.CODE
Strlen
PROC USESAXBX,String:
PTRBYTE
……
;参见例10.1
Strlen
ENDP
Strncpy
PROC USESAXCXDISIDSES,str1:
FARPTRBYTE,str2:
FARPTRBYTE,idx:
WORD,num:
WORD
LES
DI,str1
LDS
SI,str2
;取两个字符串的首地址
INVOKE
Strlen,SI
;计算源字符串的长度,在CX中
MOV
AX,idx
.IFAX>=CX
;若字符起点就超过源串的长度
MOV
BYTEPTRES:
[DI],0
;拷贝的字符串为“空”
JMP
over
.ENDIF
ADD
SI,AX
;定源串中字符的起点SI
MOV
CX,num
CLD
.REPEAT
LODSB
STOSB
.UNTILCXZAL==0
.IFAL!
=0
;设置目标串的结束符
MOV
BYTEPTR[DI],0
.ENDIF
over:
RET
Strncpy
ENDP
.STARTUP
INVOKE
Strncpy,ADDRstr2,ADDRstr1,3,5
.EXIT
0
END
例10.4编写一个把字符串中空格和TAB压缩掉的子程序Compress,字符串String是以ASCII码0为结束符。
解:
.MODEL
SMALL,C
.DATA
SPACE
EQU 20H
TAB
EQU 9H
Buff
DB "1234 Ab cdef",0
.CODE
Compress
PROC USESAXBXSIDS,String:
FARPTRBYTE
LDS
SI,String
;SI用于扫描字符串的指针
MOV
BX,SI
;BX用于存放结果的指针
.REPEAT
MOV
AL,[SI]
INC
SI
.IFAL!
=SPACE&&AL!
=TAB
MOV
[BX],AL
INC
BX
.ENDIF
.UNTILAL==0
RET
Compress
ENDP
.STARTUP
INVOKE Compress,ADDRBuff
.EXIT
0
END
从上面四个例子,我们不难看出处理字符串的一般方法,感兴趣的读者可自行编写实现字符串变小写、整体拷贝、逆转和查找等功能的子程序,甚至还可以建立起自己的字符串处理库文件。
10.2数据的分类统计程序
数据的分类和统计也是一类非数值计算,数据的分类统计方法在例6.10中已介绍,下面通过一个例子介绍数据的分类存储问题。
例10.5统计从地址0040H:
0000H开始的100个字中,把正数和负数按照它们先后出现的次序分别存储在缓冲区Data1和Data2,并把每类的个数存入相应缓冲区的第一个字单元中。
解:
由于在指定地址之后的100个字中,可能存在全是正数或负数的情况,所以,缓冲区Data1和Data2的容量都应是100个字。
.MODEL SMALL
.DATA
Num=100
Data1
DW ?
Numdup(?
)
Data2
DW ?
Numdup(?
)
.CODE
.STARTUP
MOV
AX,40H
MOV
ES,AX
LEA
SI,Data1+2
;指向存储正数的缓冲区
LEA
DI,Data2+2
;指向存储负数的缓冲区
XOR
BX,BX
;BX用于扫描存储单元
MOV
CX,100
;字符个数
.REPEAT
MOV
AX,ES:
[BX]
ADD
BX,2
CMP
AX,0
.CONTINUE .IF ZERO?
JL
next1
MOV
[SI],AX
;向正数缓冲区存储数据
ADD
SI,2
.CONTINUE
next1:
MOV
[DI],AX
;向负数缓冲区存储数据
ADD
DI,2
.UNTILCXZ
SUB
SI,OFFSETData1+2
SUB
DI,OFFSETData2+2
SHR
SI,1
SHR
DI,1
MOV
Data1,SI
MOV
Data2,DI
;把每类的统计个数存入缓冲区的第一个字单元
.EXIT
0
END
例10.6用键盘输入任意一字符串,分类统计该字符串中每个数字和字母的出现次数。
解:
.MODEL SMALL
.DATA
N=80
Buff
DBN,?
NDUP(?
)
Num
DW36DUP(0)
;每个字用于存放'0'~'9','A'~'Z'出现的个数
.CODE
.STARTUP
LEA
DX,Buff
MOV
AH,0AH
INT
21H
;输入一个字符串
XOR
CH,CH
MOV
CL,Buff+1
;CX=输入字符串的个数
LEA
SI,Buff+2
XOR
BX,BX
.REPEAT
MOV
BL,[SI]
;考虑下面的思考题
INC
SI
.IF BL>='0'&&BL<='9'
;分类统计'0'~'9'中的每个数字的个数
SUB
BL,'0'
ADD
BX,BX
INC
Num[BX]
.CONTINUE
.ENDIF
.IF BL>='a'&&BL<='z'
SUB
BL,20H
;小写变大写
.ENDIF
.IF BL>='A'&&BL<='Z'
;分类统计'A'~'Z'中的每个字母的个数
SUB
BL,'A'-10
ADD
BX,BX
INC
Num[BX]
.ENDIF
.UNTILCXZ
.EXIT 0
END
思考题:
在本例中,用指令“MOV BL,[SI]”来把当前检测的字符存入BL,当然,我们也可以用AL来代替BL,有关指令要作相应的改动,但这样做,会更方便吗?
希望读者能知道:
为什么要用BL,而不用AL?
10.3数据转换程序
数据类型转换是输入输出过程中经常遇到的问题。
输入时,计算机系统要把用户从键盘上输入的字符串转变成相应的数值,并存储在存中;输出时,要把计算机部的二进制数据形式转换成相应的十进制字符串,然后再输出。
在高级语言编程环境中,程序员能用各种输入输出语句,按一定的格式进行交互式操作,很少或根本不关心输入输出是如何实现的。
有的程序员甚至认为其输入的就是十进制数值,输出数据也就是把存中存储的数据直接输出出来。
其实,输入输出过程并不是如此简单,计算机系统要进行复杂而又细致的数据类型转换和格式化等工作。
本节试图通过用汇编语言实现数据类型的转换来反映输入输出的本来面目,使程序员在用高级语言编程时,对其输入输出语句的实现过程有所了解,也知道有别人(或编译程序)帮他完成了输入输出的准备工作。
例10.7编写一个程序,它能把字类型变量的数值以十进制形式输出出来。
若该数值为负数,则需要输出负号"-",否则,不输出符号。
解:
鉴于按二进制输出的特殊性,我们可以把它优化成例10.8的形式,按十六进制输出也可以按“四位二进制对应一位十六进制”的规则进行优化的。
例10.8编写程序,它能把字类型变量的数值以二、八进制或十六进制形式输出出来。
若该数值为负数,则需要输出负号"-",否则,不输出符号。
解:
一、按二进制形式输出的程序
二、按八进制形式输出的程序
三、按十六进制形式输出的程序
例10.7是用“用16位除10”的方法从低向高依次得到每位的数值,但若待输出的数据是32位,用10除之后,其商很可能会超过16位,所以,不能简单地引用例10.7的方法来输出32位二进制。
假设:
32位二进制数Z为A×216+B,其中:
A和B都是16位二进制数。
用10去除A,得:
A=A1×10+A2,于是,
(1)
假设A2×216+B被10除后所得的商和余数分别为B1和C1(B1≥0,C1≥0)。
利用式
(1)和“A2<10”,我们不难看出:
Z的个位就是C1和B1<216。
令Z1=A1×216+B1,显然,Z1就是Z/10所得到的商。
对于Z1,再利用式
(1)得到商Z2和C2。
……,重复上面的步骤,直到所得商为0为止。
下面的例10.9就是利用上面方法来输出32位二进制数值。
例10.9编写一个子程序,该子程序能把32位二进制变量的数值以十进制形式输出出来。
若该数值为负数,则需要输出负号"-",否则,不输出符号。
解:
.MODEL SMALL,C
.DATA
CR=13
LF=10
Data1
DD 908976789
.CODE
;子程序Display是按十进制输出32位二进制数值SOURCE
Display
PROCUSESAXBXCXDXSIDISOURCE:
DWORD
LOCAL
FLAG:
BYTE
;定义一个字节类型的局部变量FLAG
MOV
BX,WORDPTR[SOURCE]
MOV
CX,WORDPTR[SOURCE+2]
MOV
FLAG,0
;FLAG=0——正数
CMP
CX,0
JGE
next
INC
FLAG
;FLAG=1——负数
NOT
BX
NOT
CX
ADD
BX,1
;能否用指令INCBX?
ADC
CX,0
;上四条指令把32位数CX-BX变为正数
next:
XOR
DI,DI
;压入堆栈字符的个数
MOV
SI,10
;用10来除
.REPEAT
;本循环把32位二进制数转换成十进制
XOR
DX,DX
;数的字符串存入堆栈之中
MOV
AX,CX
DIV
SI
MOV
CX,AX
MOV
AX,BX
DIV
SI
ADD
DL,'0'
PUSH
DX
INC
DI
MOV
BX,AX
.UNTIL
BX==0&&CX==0
.IF FLAG==1
;判断前面转换的数是否为负数
MOV
AL,'-'
;若是,把符号'-'压入堆栈
PUSH
AX
INC
DI
.ENDIF
MOV
CX,DI
.REPEAT
;本循环把堆栈中的字符串显示出来
POP
DX
MOV
AH,2
INT
21H
.UNTILCXZ
MOV
DL,CR
;下面六条指令显示回车、换行
MOV
AH,2
INT
21H
MOV
DL,LF
MOV
AH,2
INT
21H
RET
Display
ENDP
.STARTUP
INVOKE
Display,Data1
INVOKE
Display,-123456789
.EXIT
0
END
例10.10编写一个程序,它能把用键盘输入的字符串转化成相应的数值。
具体功能如下:
1、
输入的数据字符串可以带正、负符号,如:
1234、+1234或-1234;
2、
字符串的最后一个字符表示数据的进制,默认的进制为十进制,如:
1234H表示十六进制数1234,1234为十进制数;
3、
对于任何进制的数据,当遇到一个非进制围的字符时,则显示出错信息,并以数值为其转换结果来结束该类型转换过程。
解:
略
10.4文件操作程序
有关目录和顺序文件的操作在第8.3.6节中已有介绍和举例,本节主要介绍对记录文件的读写方法。
记录文件是指文件中的每个分量是一个结构的文件,如:
Fox系列数据库管理系统中的DBF文件,该文件除了文件头是由记录文件的整体信息和各字段描述信息之外,文件的主体容就是由同一个结构组成的。
下面通过二个例子来介绍记录文件的读写方法。
例10.11假设有一个简单的学生结构类型student,其包括:
学号、和年龄等信息,要求编写一个程序,该程序接受从键盘输入的学生记录信息,并把它们保存在文件students.dat之中。
解:
.MODELSMALL,C
.486
student
STRUCT
id
DW?
sname
DB10DUP(?
)
age
DB?
student
ENDS
.DATA
fname
DB "Students.dat",0
msg1
DB "Id:
$"
msg2
DB "Name:
$"
msg3
DB "Age:
$"
msg4
DB "Continue?
$"
msg5
DB "Failtocreatefile$"
CRLF
DB 0AH,0DH,"$"
buff
DB ?
?
11DUP(?
)
peason
STUDENT<>
.CODE
DispMsg
PROCUSESAXDX,Msg:
PTRBYTE
;显示字符串Msg
……
;参见例10.7
DispMsg
ENDP
;程序功能:
把字符串Data转化成数值,不考虑负数。
当遇到非法字符时,则结束转换操作;
;入口参数:
Data为字符串的首地址,Len为该字符串的长度;
;出口参数:
数值存放在AX中。
GetData
PROCUSESBXCXSI,Len:
BYTE,Data:
PTRBYPE
XOR
CX,CX
MOV
CL,Len
MOV
SI,Data
XOR
AX,AX
XOR
BX,BX
.REPEAT
MOV
BL,[SI]
SUB
BL,'0'
.BREAK.IFBL<0||BL>9
;判断当前数值是否在0~9之间
IMUL
AX,10
ADD
AX,BX
INC
SI
.UNTILCXZ
RET
GetData
ENDP
;程序功能:
读取指定长度的字符串,在输入前,显示有关输入容的提示信息;
;入口参数:
读入字符串的长度为Len,提示信息的首地址为MSG;
;出口参数:
读入信息(字符串)存放缓冲区buff中。
GetInfo
PROC USESAXDX,Len:
BYTE,Msg:
PTRBYTE
INVOKE
DispMsg,Msg
;显示提示信息
MOV
AL,Len
MOV
buff,AL
MOV
AH,0AH
LEA
DX,buff
INT
21H
INVOKE
DispMsg,ADDRCRLF
;显示回车、换行
RET
GetInfo
ENDP
.STARTUP
MOV
AX,DS
MOV
ES,AX
LEA
DX,fname
MOV
CX,20H
MOV
AH,3CH
INT
21H
;创建文件
.IFCARRY?
;若创建失败,则显示失败信息
INVOKE DispMsg,ADDRmsg5
JMP over
.ENDIF
MOV
BX,AX
;把句柄存入BX,为后面使用作准备
again:
INVOKE
DispMsg,ADDRCRLF
;显示回车、换行
INVOKE
GetInfo,5,ADDRmsg1
;读取学号(假定学号为4位整数)
INVOKE
GetData,4,ADDRbuff+2
;把学号字符串转化成数值
MOV
peason.id,AX
;把数值型学号存入学号字段
INVOKE
GetInfo,11,ADDRmsg2
;读取(假定为10个字符)
MOV
CX,10
MOV
AL,''
LEA
DI,peason.sname
REP
STOSB
;先置字段为10个空格
MOV
CL,buff+1
MOV
SI,OFFSETbuff+2
LEA
DI,peason.sname
REP
MOVSB
;把输入的存入字段
INVOKE
GetInfo,3,ADDRmsg3
;读取年龄(假定年龄为2位整数)
INVOKE
GetData,2,ADDRbuff+2
;把年龄字符串转化成数值
MOV
peason.age,AL
;把数值型年龄存入年龄字段
MOV
CX,SIZEpeason
LEA
DX,peason
MOV
AH,40H
INT
21H
;把学生记录写入文件
INVOKE
DispMsg,ADDRmsg4
;提示是否继续输入
MOV
AH,1
INT
21H
AND
AL,0DFH
CMP
AL,'Y'
JZ
again
;若按y或Y,则继续输入
MOV
AH,3EH
INT
21H
over:
.EXIT
0
END
例10.12编写一个程序显示由例10.11建立的记录文件students.dat中的学生信息。
解:
.MODEL SMALL,C
student
STRUCT
id
DW ?
sname
DB 10DUP(?
)
age
DB ?
student
ENDS
.DATA
fname
DB "Students.dat",0
id1
DB "Id:
",4dup(?
),0dh,0ah,"$"
name1
DB "Name:
",10dup(''),0dh,0ah,"$"
age1
DB "Age:
",2dup(?
),0dh,0ah,"$"
msg1
DB "Failtoopenfile$"
peason
student <>
.CODE
DispMsg
PROCUSESAXDX,Msg:
PTRBYTE
;显示字符串Msg
……
;参见例10.7
DispMsg
ENDP
;程序功能:
把数据Data转换成长度为Len的字符串;
;入口参数:
待转换数据Data,转换成字符串的长度为Len,存放字符串的首地址为PStr;
;出口参数:
读入信息(字符串)存放缓冲区buff中。
GetStr
PROCUSESAXCXDXDI,Data:
WORD,Len:
WORD,PStr:
PTRBYTE
MOV
CX,Len
MOV
DI,PStr
MOV
AL,''
REP
STOSB
;把存放字符串的缓冲区填充为空格
MOV
DI,PStr
ADD
DI,Len
DEC
DI
;确定最后一个字符在缓冲区中的位置
MOV
AX,Data
MOV
CX,10
.REPEAT
XOR
DX,DX
IDIV
CX
;除10,从低位向高位求得每一位
ADD
DL,'0'
;把余数转变成字符,然后存放目标单元
MOV
[DI],DL
DEC
DI
.UNTIL AX==0
RET
GetStr
ENDP
.STARTUP
MOV
AX,DS
MOV
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 汇编语言 应用程序 设计 说明