⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇010.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 3 页
字号:
了解的内容:打印机输出、磁盘输入输出、通信口输入输出和异常情况处理等程序的编程方法,程序段前缀PSP的含义及其应用。

掌握的内容:驻留程序的设计方法,结构和记录在汇编语言中的应用方法,文件操作的编程,鼠标(Mouse)应用程序的编程。

熟练掌握的内容:处理键盘输入的各种方法,屏幕的定位和显示方法,字符串的处理方法,二进制数据和字符串之间的转换方法。

建议学习时间:12小时。
第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 "This is a example.", 0 
.CODE 
Strlen PROC USES AX BX, String:PTR BYTE 
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, ADDR buff 
.EXIT 0 
END 
例10.2 编写一个把字符串中的所有小写字符转换成大写字符的子程序Strupr,要求字符串的首地址和结束符为其入口参数。 

解: 
 .MODEL SMALL, C 
.DATA 
buff
 DB   "This is a example.", 0 
.CODE 
Strupr PROC   USES AX BX, String:PTR BYTE, 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, ADDR buff, 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 20 DUP('A') 
.CODE 
Strlen PROC  USES AX BX, String:PTR BYTE 
…… ;参见例10.1 
Strlen ENDP 
Strncpy PROC  USES AX CX DI SI DS ES, str1:FAR PTR BYTE, str2:FAR PTR BYTE, idx:WORD, num:WORD 
LES DI, str1 
LDS SI, str2 ;取两个字符串的首地址 
INVOKE Strlen, SI ;计算源字符串的长度,在CX中 
MOV AX, idx 
.IF AX >= CX ;若字符起点就超过源串的长度 
MOV
 BYTE PTR ES:[DI], 0 ;拷贝的字符串为“空” 
JMP
 over 
.ENDIF 
ADD SI, AX ;定源串中字符的起点SI 
MOV CX, num 
CLD 
.REPEAT 
LODSB
 
STOSB
 
.UNTILCXZ AL==0 
.IF AL!=0 ;设置目标串的结束符 
MOV
 BYTE PTR[DI], 0 
.ENDIF 
over: RET 
Strncpy ENDP 
.STARTUP 
INVOKE Strncpy, ADDR str2, ADDR str1, 3, 5 
.EXIT 0 
END 
例10.4 编写一个把字符串中空格和TAB压缩掉的子程序Compress,字符串String是以ASCII码0为结束符。 

解: 
 .MODEL SMALL, C 
.DATA 
SPACE
 EQU 20H 
TAB
 EQU 9H 
Buff
 DB "12 3 4   Ab  cdef", 0 
.CODE 
Compress PROC USES AX BX SI DS, String:FAR PTR BYTE 
LDS SI, String ;SI用于扫描字符串的指针 
MOV BX, SI ;BX用于存放结果的指针 
.REPEAT 
MOV
 AL, [SI] 
INC
 SI 
.IF AL!=SPACE && AL!=TAB
 
 MOV [BX], AL 
INC BX  
.ENDIF
 
.UNTIL AL==0 
RET 
Compress ENDP 
.STARTUP 
INVOKE Compress, ADDR Buff 
.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 ?, Num dup(?) 
Data2
 DW ?, Num dup(?) 
.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, OFFSET Data1+2 
SUB
 DI, OFFSET Data2+2 
SHR
 SI, 1 
SHR
 DI, 1 
MOV
 Data1, SI 
MOV 
 Data2, DI  ;把每类的统计个数存入缓冲区的第一个字单元 
.EXIT
 0 
END 
 例10.6 用键盘输入任意一字符串,分类统计该字符串中每个数字和字母的出现次数。 

解: 
 .MODEL SMALL 
.DATA 
N = 80
 
Buff
 DB N, ?, N DUP(?) 
Num
 DW 36 DUP(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.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 PROC USES AX BX CX DX SI DI SOURCE:DWORD 
LOCAL FLAG:BYTE ;定义一个字节类型的局部变量FLAG 
MOV BX, WORD PTR [SOURCE] 
MOV CX, WORD PTR [SOURCE+2] 
MOV FLAG, 0 ;FLAG=0——正数 
CMP CX, 0 
JGE next 
INC FLAG ;FLAG=1——负数 
NOT BX 
NOT CX 
ADD BX, 1 ;能否用指令INC BX? 
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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -