解决了字符串的输入与输出,现在来考虑这样一个问题:如何在一个字符串中查找一个给定的字符?下面给出了一般的解决方法:
data segment assume ds:data mess db 'Price: $1.00',0dh,0ah,0 ;定义一个含有'$'的字符串 ascii db '0123456789ABCDEF' ;十六进制数字对应的ASCII码 errmsg db 07h,'Character not found!', 0dh,0ah,'$' data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器指向数据段 mov ds,ax mov si,offset mess ;SI寄存器指向字符串MESS mov cx,0 ;CX寄存器清0,准备计字符数 outchar: mov al,byte ptr [si] ;取一个字符送入AL寄存器 cmp al,'$' ;是所要找的'$'符吗? jz out_cx ;若是则转OUT_CX输出CX寄存器中的值 cmp al,0 ;到字符串结尾了吗? jz not_fd ;显示出错信息并退出 inc cx ;CX寄存器加1 out_cx: inc si ;SI寄存器指向下一个字符 jmp outchar ;判断下一个字符 mov ax,cx ;CX寄存器存入AX寄存器 outloop: mov bx,offset ascii ;BX寄存器指向ASCII表 mov cx,4 ;处理4个数位 rol ax,1 ;循环左移4位,将高4位移至低4位 rol ax,1 rol ax,1 rol ax,1 push ax ;暂存AX寄存器 and ax,000fh ;保留低4位 xlat ;取得对应的ASCII码 mov ah,0eh ;利用10H中断的0EH功能 int 10h ;输出AL中的字符 pop ax ;取回AX寄存器 loop outloop ;处理下一个数位 exit: mov ah,4ch ;结束程序 int 21h not_fd: mov dx,offset errmsg mov ah,09h int 21h jmp exit main endp code ends end main
程序中并没有使用LODS指令,而是把SI寄存器作为一个可以作间接寻址的一般寄存器应用。如何使用串处理指令解决这个问题呢?请看下面的程序:
data segment assume ds:data mess db 'Price: $1.00',0dh,0ah,0 ascii db '0123456789ABCDEF' errmsg db 07h,'Character not found!',0dh,0ah,'$' ;字符未找到 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS、ES寄存器指向数据段 mov ds,ax mov es,ax mov di,offset mess ;DI寄存器指向字符串MESS mov cx,14 ;在14个字符中查找'$' mov al,'$' ;要查找的字符是'$' repnz scasb ;扫描字符串 jz out_cx ;找到'$'后转至OUT_CX jmp not_found ;未找到'$'则转至NOT_FOUND out_cx: sub di,offset mess+1 ;计算'$'符的偏移位置 mov ax,di ;偏移位置送入AX寄存器 mov bx,offset ascii ;BX寄存器指向ASCII表 mov cx,4 ;处理4个数位 outloop: rol ax,1 ;AX寄存器向左循环移4位 rol ax,1 rol ax,1 rol ax,1 push ax ;暂存AX寄存器 and ax,000fh ;保留AX寄存器的低4位 xlat ;取得对应的ASCII码 mov ah,0eh ;利用10H中断的0EH功能 int 10h ;显示AL寄存器中的字符 pop ax ;取回AX寄存器 loop outloop ;处理下一个数位 jmp exit ;转至EXIT结束程序 not_found: mov dx,offset errmsg ;显示出错信息 mov ah,9 int 21h exit: mov ah,4ch ;结束程序 int 21h main endp code ends end main
程序中新出现了一个寄存器--DI(Destination Index)。
DI称为目的地址索引寄存器,它和SI寄存器一样用于保存串处理指令需要用到的地址,但这个寄存器指示的是"目的地址",也就是说它和LODS这样的指令没有任何关系。只有那些具有"写"数据操作的串指令或串扫描、串比较指令才会使用DI寄存器中的地址。
当然DI寄存器也可以作间接寻址用,这和SI寄存器是一样的。还有一点需要注意的是在使用串处理指令时这个寄存器是和附加段寄存器ES相配合给出逻辑地址,只有在不用于串指令而作一般的间接寻址用时,才默认DS为段地址。
回顾一下上面的程序,我们在设定DS寄存器指向DATA段后又用MOV ES,AX指令将ES寄存器设为DATA段,目的就在于为后面的SCAS指令建立正确的字符串地址。那么SCAS指令又具有什么作用呢?
助记符:SCAS(Scan string)
用 途:在"目的串"中搜索给定的数据
格 式:SCASB(搜索一字节)
SCASW(搜索一个字)
执 行:将位于ES:DI处的数据(字节或字)与累加器中的数据进行比较,并根据结果设定标志位,同时DI寄存器根据DF标志变化。
和LODS一样,指令末尾的"B"和"W"表示所要搜索的数据位宽,DI寄存器究竟变化1还是2就由这两个字母决定。不过这个指令有个易搞混的问题,就是单独使用这个指令时是否会将字符串中所有数据都处理一次?
大家不要被它的名字蒙住,它虽然叫串扫描指令,但如果我们单独使用这个指令,它只会将ES:DI指向的数据与累加器相比,而后改变DI寄存器,并不像我们所想的那样将整个串中所有数据都扫一遍。而我们所需要的恰好是扫描整个串,这又该如何应用SCAS指令呢?
幸好SCAS指令可以配合一个前缀,这个前缀就是:
助记符:REP(Repeat)
用 途:作为前缀使后面的串指令重复执行,重复次数在CX中设定。
格 式:REP 串处理指令
执 行:判断CX,若CX不为0,则CX寄存器减1,执行后面的指令,重复这三个步骤直至CX=0