
- •16. Строковые команды
- •16.1. Команда пересылки строк.
- •Xor ax, ax
- •Inc_bxDb43h; код командыincbx,
- •Xorbx,bx; вbx- длина очереди
- •Xorax,ax; Счетчик несовпадающих элементов
- •Incax; Нашли совпадение — увеличить счетчик
- •Int 21h
- •Incdi; Вернуть указатель на найденный символ
- •Int 21h
- •16.7. Команды загрузки адресов
Xorax,ax; Счетчик несовпадающих элементов
mov si, OFFSET s1
mov di, OFFSET s2
comp:repecmpsb; Повторять, пока совпадение
jefin; Исчерпали строки — закончить
Incax; Нашли совпадение — увеличить счетчик
orcx,cx; Строки исчерпаны?
jnecomp; Нет — продолжим сравнение
fin: mov ax, 4C00h
Int 21h
END start
Для строк, указанных в программе, количество несовпадений равно 1.
Пример. В строке отыскать адрес последнего вхождения буквы 'z'.
string db "asdzbxzar",0
...
mov ax, @data
mov es, ax
cld
mov al,0
mov di, OFFSET string
movcx, -1
repnescasb; Найти конец строки
decdi; Переместить указатель на 0
std; Поиск в направлении уменьшения адресов
mov al, 'z'
mov cx, -1
repnescasb
Incdi; Вернуть указатель на найденный символ
; В DI— адрес символа
...
Эта программа некорректна. Она правильно работает, если в строке заведомо имеется символ 'z'.
Упражнение. Переработать этот фрагмент так, чтобы программа корректно работала и при отсутствии символа 'z'.
Пример. В строке превратить прописные буквы в строчные.
.MODEL small
.STACK 100h
.DATA
string DB "aSd1-E"
lenstr = $ - string
.CODE
start:mov ax,@data
mov ds,ax
mov es,ax
mov si, OFFSET string
mov di,si
mov cx,lenstr
cld
L: lodsb
cmp al,'A'
jnae m
cmp al,'Z'
jnbe m
add al, 'a'-'A'
m: stosb
loop L
mov ax,4C00h
Int 21h
END start
Часть цикла можно было переписать эффективнее:
add al, 'a'-'A'
stosb
loop L
jmp short fin
m: inc di
loop L
fin: mov ax,4C00h
Тогда не происходит лишнего обращения к памяти, а только перемещается указатель.
А теперь пример на новые возможности 386-го процессора.
Пример. Заполнить массив двойных слов числом 12345678h. Сразу посмотрим листинг.
1 0000 MODEL small
2 .386
3 0000 STACK 100h
4 0000 .DATA
5 0000 0C*(00000000) arr DD 12 DUP(0)
6 0030 .CODE
7 0000 B8 0000s start:mov ax,@data
8 0003 8E D8 mov ds,ax
9 0005 8E C0 mov es,ax
10 0007 66| B8 12345678 mov eax,12345678h
11 000D 66| B9 0000000C mov ecx,12
12 0013 66| BF 00000000r mov edi,OFFSET arr
13 0019 FC cld
14 001A F3> 66| AB rep stosd
15 001D B8 4C00 mov ax,4C00h
16 0020 CD 21 int 21h
17 END start
Отметим , что в листинге для команды rep stosd имеется два префикса: 66 — префикс размера операнда, и F3 — префикс повторения.
И еще замечание, не имеющее отношения к строковым операциям. Вместо команды mov ecx,12 можно написать mov cx,12, а вместо mov edi,OFFSET arr — mov di,OFFSET arr. Убедимся, например, во втором утверждении. Заменим команду mov edi,OFFSET arr двумя командами:
mov edi, 0FFFF0000h
mov di,OFFSET arr
В отладчике можно убедиться, что заполнение массива происходит правильно. 32-разрядный адрес преобразуется в 16-разрядный посредством отбрасывания старших разрядов.
16.7. Команды загрузки адресов
Для целей дальнейшего изложения здесь уместно ввести команды ldsиles, Которые к строковым командам не имеют прямого отношения.
Ранее была введена команда lea— загрузить эффективный (исполнительный) адрес. Вот еще две команды.
Загрузить указатель в сегменте данных |
lds reg,src |
reg src DS src + 2 |
(Load pointer using DS) |
флаги не изменяются |
Загрузить указатель в дополнительном сегменте данных |
les reg,src |
reg src ES src + 2 |
(Load pointer using ES) |
флаги не изменяются |
Источником srcдля этих команд служит операнд — двойное слово. Младшее слово загружается в регистр-указатель (как правило,SIилиDI), а старшее — в сегментный регистр.