ITEEDU

5.3 数据串处理

5.3节导航:第一页 第二页 第三页 第四页 第五页

 什么是"串"?一般来说在内存中连续存放的一系列位宽一致的数据就可以称为一个串。最为常见的就是以"$"结尾的一个字符串。8086/88和与其完全兼容的CPU有几个专门的寄存器和一些指令用于处理数据串,这些专门的指令就是所谓的"串指令"。这些寄存器和指令就是这一节主要讨论的内容。这一节将结束对8086/88内部寄存器的讨论(标志寄存器除外),在后面的学习中这些知识有助于设计出更灵活的程序。

由于字符串比较常用,而且也较为直观,所以后面所举实例基本都以字符串为代表。下面我们就来讨论第一个简单的问题:字符串的输入。
我们在第三章中介绍了单字符的输入方法:调用INT 21H的1号功能。用此功能配合一点程序设计技术也可以完成字符串的输入。请看下面的程序:

GETSTR.ASM
        data  segment
              assume    ds:data
        mess  db        0dh,0ah
      buffer  db        10 dup(20h)		;定义10个空格作为存储字符串的缓冲区
              db        '$'				;定义一个'$'作为字符串结束符
        data  ends
			
        code  segment
              assume    cs:code
        main  proc      far
              mov       ax,data			;初始化DS寄存器指向数据段
              mov       ds,ax
			
              mov       bx,offset buffer	;BX寄存器指向字符串缓冲区
      input:
              mov       ah,1			;选择DOS API的01功能
              int       21h				;等待键盘输入
              mov       byte ptr [bx],al	;将键盘输入的字符存入缓冲区
              inc       bx				;缓冲区指针加1
              cmp       al,0dh			;输入的字符是回车符吗?
              jnz       input			;不是回车符则返回INPUT处继续接收字符
              mov       byte ptr [bx],0ah	;是回车符,在回车符后面填入一个换行符
			
              mov       dx,offset mess	;DX寄存器指向MESS
              mov       ah,9			;显示输入的字符串
              int       21h
			
              mov       ah,4ch			;结束进程
              int       21h
        main  endp
        code  ends
              end       main

 在程序的数据区内定义了10BYTES的存储区用于存放字符,我们把这个存储区称为字符的"缓冲区"。后面的程序连续用INT 21H的1号功能接收字符并存入缓冲区内,直至收到回车符。采用这种方法接收字符串有两个缺陷:一是不好限制输入字符串的长度,尽管只定义了10个BYTE的缓冲区;二是字符一经输入就不好改变,你必须保证一次输入正确。当然我们可以增加代码解决这两个问题,不过就这个问题而言最佳的解决方法就是采用DOS提供的一个功能调用接收字符串,这就是INT 21H的0AH功能:

功能号:0AH
用 途:从键盘接收一个字符串到缓冲区中。
参 数:AH=0AH
DS:DX指向输入缓冲区首

调 用:INT 21H
返 回:无

此功能的用法并不难,关键在于缓冲区的格式有些特别:

字节0:缓冲区能容纳的字符数(编程时给出)
字节1:缓冲区中已输入的字符数(DOS返回值)
字节2-缓冲区末尾:存放输入的字符

程序GETSTR1.ASM是这个功能的应用实例:

GETSTR1.ASM
        data  segment
              assume    ds:data
      buffer  db        10,?		;定义字符串缓冲区
              db        10 dup(20h)
        data  ends
        code  segment
              assume    cs:code
        main  proc      far
              mov       ax,data		;初始化DS寄存器指向数据段
              mov       ds,ax
              mov       dx,offset buffer	;DX寄存器指向字符串缓冲区
              mov       ah,0ah		;选择DOS API的0AH功能
              int       21h			;等待键盘输入字符串
              mov       ah,4ch		;结束进程
              int       21h
        main  endp
        code  ends
              end       main

 这个程序不会在屏幕上显示什么结果,我们的目的是用DEBUG跟踪这个程序来分析DOS的这个功能:

-g=0 8[Enter]
AX=0E8E BX=0000 CX=0020 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0E8E ES=0E7E SS=0E8E CS=0E8F IP=0008 NV UP EI PL NZ NA PO NC
0E8F:0008 B40A MOV AH,0A

 先在CS:0008处打一个断点,执行DOS的0AH功能前我们先来观察一下程序定义的缓冲区的情况。

d0:f?    缓冲区中最多可存的字符数
0E8E:0000?    0A 00 20 20 20 20 20 20-20 20 20 20 00 00 00 00
字符计数值?   预存于缓冲区中的10个空格

 继续使用"G"命令在CS:000C处设置断点,同时从键盘输入字符串"ASSEMBLY"并回车。

-g=8 c[Enter]
assembly[Enter]     键盘输入的字符串
AX=0A0D BX=0000 CX=0020 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0E8E ES=0E7E SS=0E8E CS=0E8F IP=000C NV UP EI PL NZ NA PO NC
0E8F:000C B44C MOV AH,4C

 现在我们再次观察一下字符串缓冲区,看看有什么变化。

d0:f    字符串计数值发生变化,说明从键盘输入了8个字符
0E8E:0000  0A 08 61 73 73 65 6D 62-6C 79 0D 20 00 00 00 00..assembly. ....

键盘输入的字符串

不难看出字节1是由DOS填写的,这个数字并不包括末尾的回车符;输入的字符串末尾只有回车符,无换行符。

采用这个功能不仅编程简单,而且DOS还会根据我们给定的字节0的值限制输入字符的数量,同时如果我们输入有错,我们还可以用退格键修改。运行这个程序试一下就能验证这两个特点。