汇编语言之应用程序的设计说明.docx

上传人:b****6 文档编号:7448810 上传时间:2023-01-24 格式:DOCX 页数:31 大小:33.31KB
下载 相关 举报
汇编语言之应用程序的设计说明.docx_第1页
第1页 / 共31页
汇编语言之应用程序的设计说明.docx_第2页
第2页 / 共31页
汇编语言之应用程序的设计说明.docx_第3页
第3页 / 共31页
汇编语言之应用程序的设计说明.docx_第4页
第4页 / 共31页
汇编语言之应用程序的设计说明.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

汇编语言之应用程序的设计说明.docx

《汇编语言之应用程序的设计说明.docx》由会员分享,可在线阅读,更多相关《汇编语言之应用程序的设计说明.docx(31页珍藏版)》请在冰豆网上搜索。

汇编语言之应用程序的设计说明.docx

汇编语言之应用程序的设计说明

第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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1