汇编语言之应用程序的设计说明Word格式.docx
《汇编语言之应用程序的设计说明Word格式.docx》由会员分享,可在线阅读,更多相关《汇编语言之应用程序的设计说明Word格式.docx(31页珍藏版)》请在冰豆网上搜索。
"
Strupr
PROC
USESAXBX,String:
PTRBYTE,Tail:
BYTE
.REPEAT
.IF AL>
='
a'
&
&
AL<
z'
SUB
AL,20H
[BX],AL
.ENDIF
.UNTIL
AL==Tail
INVOKE Strupr,ADDRbuff,0
例10.3编写一个从字符串中拷贝子串的子程序Strncpy,它有四个参数str1、str2、idx和num,其具体功能为把字符串str2中从第idx个(从0开始记数)字符开始、num个字符传送给str1,字符串str1和str2都是以ASCII码0为结束符。
.MODEL
str1
12345ABCDEF"
str2
DB 20DUP('
A'
)
PROC
USESAXBX,String:
……
;
参见例10.1
Strncpy
USESAXCXDISIDSES,str1:
FARPTRBYTE,str2:
FARPTRBYTE,idx:
WORD,num:
WORD
LES
DI,str1
LDS
SI,str2
取两个字符串的首地址
INVOKE
Strlen,SI
计算源字符串的长度,在CX中
AX,idx
.IFAX>
=CX
若字符起点就超过源串的长度
BYTEPTRES:
[DI],0
拷贝的字符串为“空”
JMP
over
ADD
SI,AX
定源串中字符的起点SI
CX,num
CLD
LODSB
STOSB
.UNTILCXZAL==0
.IFAL!
设置目标串的结束符
BYTEPTR[DI],0
over:
Strncpy,ADDRstr2,ADDRstr1,3,5
.EXIT
例10.4编写一个把字符串中空格和TAB压缩掉的子程序Compress,字符串String是以ASCII码0为结束符。
SPACE
EQU 20H
TAB
EQU 9H
Buff
1234
Ab
cdef"
Compress
PROC USESAXBXSIDS,String:
FARPTRBYTE
SI,String
SI用于扫描字符串的指针
BX,SI
BX用于存放结果的指针
AL,[SI]
SI
=SPACE&
AL!
=TAB
.UNTILAL==0
INVOKE Compress,ADDRBuff
从上面四个例子,我们不难看出处理字符串的一般方法,感兴趣的读者可自行编写实现字符串变小写、整体拷贝、逆转和查找等功能的子程序,甚至还可以建立起自己的字符串处理库文件。
10.2数据的分类统计程序
数据的分类和统计也是一类非数值计算,数据的分类统计方法在例6.10中已介绍,下面通过一个例子介绍数据的分类存储问题。
例10.5统计从地址0040H:
0000H开始的100个字中,把正数和负数按照它们先后出现的次序分别存储在缓冲区Data1和Data2,并把每类的个数存入相应缓冲区的第一个字单元中。
由于在指定地址之后的100个字中,可能存在全是正数或负数的情况,所以,缓冲区Data1和Data2的容量都应是100个字。
.MODEL SMALL
Num=100
Data1
DW ?
Numdup(?
Data2
AX,40H
ES,AX
LEA
SI,Data1+2
指向存储正数的缓冲区
DI,Data2+2
指向存储负数的缓冲区
BX,BX
BX用于扫描存储单元
CX,100
字符个数
AX,ES:
[BX]
BX,2
CMP
AX,0
.CONTINUE .IF ZERO?
JL
next1
MOV
[SI],AX
向正数缓冲区存储数据
SI,2
.CONTINUE
next1:
[DI],AX
向负数缓冲区存储数据
DI,2
.UNTILCXZ
SI,OFFSETData1+2
DI,OFFSETData2+2
SHR
SI,1
DI,1
Data1,SI
Data2,DI
把每类的统计个数存入缓冲区的第一个字单元
END
例10.6用键盘输入任意一字符串,分类统计该字符串中每个数字和字母的出现次数。
N=80
DBN,?
NDUP(?
Num
DW36DUP(0)
每个字用于存放'
0'
~'
9'
,'
Z'
出现的个数
DX,Buff
AH,0AH
INT
21H
输入一个字符串
CH,CH
CL,Buff+1
CX=输入字符串的个数
SI,Buff+2
BL,[SI]
考虑下面的思考题
.IF BL>
BL<
分类统计'
中的每个数字的个数
BL,'
Num[BX]
BL,20H
小写变大写
中的每个字母的个数
-10
.EXIT
0
思考题:
在本例中,用指令“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位二进制变量的数值以十进制形式输出出来。
CR=13
LF=10
DD
908976789
子程序Display是按十进制输出32位二进制数值SOURCE
Display
PROCUSESAXBXCXDXSIDISOURCE:
DWORD
LOCAL
FLAG:
定义一个字节类型的局部变量FLAG
BX,WORDPTR[SOURCE]
CX,WORDPTR[SOURCE+2]
FLAG,0
FLAG=0——正数
CX,0
JGE
next
FLAG
FLAG=1——负数
NOT
BX,1
能否用指令INCBX?
ADC
上四条指令把32位数CX-BX变为正数
next:
DI,DI
压入堆栈字符的个数
SI,10
用10来除
本循环把32位二进制数转换成十进制
DX,DX
数的字符串存入堆栈之中
AX,CX
DIV
CX,AX
AX,BX
DL,'
PUSH
DX
DI
BX,AX
.UNTIL
BX==0&
CX==0
.IF FLAG==1
判断前面转换的数是否为负数
AL,'
-'
若是,把符号'
压入堆栈
AX
CX,DI
本循环把堆栈中的字符串显示出来
POP
AH,2
DL,CR
下面六条指令显示回车、换行
DL,LF
Display,Data1
Display,-123456789
例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?
ENDS
fname
Students.dat"
0
msg1
Id:
$"
msg2
Name:
msg3
Age:
msg4
Continue?
msg5
Failtocreatefile$"
CRLF
DB 0AH,0DH,"
DB ?
?
11DUP(?
peason
STUDENT<
>
DispMsg
PROCUSESAXDX,Msg:
显示字符串Msg
参见例10.7
程序功能:
把字符串Data转化成数值,不考虑负数。
当遇到非法字符时,则结束转换操作;
入口参数:
Data为字符串的首地址,Len为该字符串的长度;
出口参数:
数值存放在AX中。
GetData
PROCUSESBXCXSI,Len:
BYTE,Data:
PTRBYPE
CL,Len
SI,Data
AX,AX
.BREAK.IFBL<
0||BL>
9
判断当前数值是否在0~9之间
IMUL
AX,10
读取指定长度的字符串,在输入前,显示有关输入容的提示信息;
读入字符串的长度为Len,提示信息的首地址为MSG;
读入信息(字符串)存放缓冲区buff中。
GetInfo
USESAXDX,Len:
BYTE,Msg:
DispMsg,Msg
显示提示信息
AL,Len
buff,AL
DX,buff
DispMsg,ADDRCRLF
显示回车、换行
AX,DS
DX,fname
CX,20H
AH,3CH
创建文件
.IFCARRY?
若创建失败,则显示失败信息
INVOKE DispMsg,ADDRmsg5
JMP over
把句柄存入BX,为后面使用作准备
again:
GetInfo,5,ADDRmsg1
读取学号(假定学号为4位整数)
GetData,4,ADDRbuff+2
把学号字符串转化成数值
peason.id,AX
把数值型学号存入学号字段
GetInfo,11,ADDRmsg2
读取(假定为10个字符)
CX,10
'
DI,peason.sname
REP
先置字段为10个空格
CL,buff+1
SI,OFFSETbuff+2
MOVSB
把输入的存入字段
GetInfo,3,ADDRmsg3
读取年龄(假定年龄为2位整数)
GetData,2,ADDRbuff+2
把年龄字符串转化成数值
peason.age,AL
把数值型年龄存入年龄字段
CX,SIZEpeason
DX,peason
AH,40H
把学生记录写入文件
DispMsg,ADDRmsg4
提示是否继续输入
AH,1
AND
AL,0DFH
Y'
JZ
again
若按y或Y,则继续输入
AH,3EH
例10.12编写一个程序显示由例10.11建立的记录文件students.dat中的学生信息。
.MODEL SMALL,C
DB 10DUP(?
id1
"
4dup(?
),0dh,0ah,"
name1
10dup('
age1
2dup(?
Failtoopenfile$"
student <
把数据Data转换成长度为Len的字符串;
待转换数据Data,转换成字符串的长度为Len,存放字符串的首地址为PStr;
GetStr
PROCUSESAXCXDXDI,Data:
WORD,Len:
WORD,PStr:
CX,Len
DI,PStr
把存放字符串的缓冲区填充为空格
DI,Len
DEC
确定最后一个字符在缓冲区中的位置
AX,Data
IDIV
除10,从低位向高位求得每一位
把余数转变成字符,然后存放目标单元
[DI],DL
.UNTIL AX==0