Две оставшиеся строковые команды используются в программах для
сравнения строковой информации. Первая из них - команда,
сканирование строки SCAS. Эта команда сравнивает значение в
регистре AL или регистре AX с операндом в памяти, на который
ссылается пара регистров ES:DI. Команда SCAS устанавливает флаги
нуля, переноса и переполнения, показывая результат сравнения
аккумулятора и ячейки памяти, и изменяет регистр DI так, чтобы он
указывал на следующий операнд в строке.
Команда SCAS не может использовать обычный префикс REP для
сканирования длинной строки информации. Точно так же, как команда
REP LODS не имеет смысла, команда REP SCAS не позволяет программе
контролировать каждое сравнение. Вместо этого существует два
варианта префикса REP - "повторять пока равно" REPE и "повторять
пока не равно" REPNE. Как и в случае обычного префикса REP,
программа загружает в регистр CX длину строки. Если указан префикс
REPE, команда выполняется ло тех пор, пока содержимое регистра AL
(или AX) не перестанет совпадать с ячейками памяти, или пока
содержимое регистра CX не станет равно 0. Пока аккумулятор
совпадает с ячейкой памяти, сканирование продолжается. Команда
REPNE в точности противоположна команде REPE. Сканирование
продолжается до тех пор, пока аккумулятор не совпадает с ячейкой
памяти.
Комбинация команд SCAS и REPNE позволяет программе выполнять
быстрый поиск по таблице. Чтобы найти объект в таблице, программа
должна перебрать каждую ячейку для сравнения с аргументом. На
Фиг. 4.24 показано, как команда SCAS выполняет эту функцию. В
регистре AL содержится аргумент сравнения. Таблица SCAN_TABLE
содержит значения, среди которых ведется поиск, а в регистре CX
находится длина таблицы. Команда REPNE SCASB сканирует таблицу до
тех пор, пока содержимое аккумулятора не станет равно элементу
строки. В этом месте регистр DI указывает на байт таблицы,
непосредственно следующий за сравнением. Вы можете определить
смещение совпавшего объекта, вычитая единицу из регистра DI после
метки FOUND. Программа может использовать эту информацию для
доступа к другой таблице, или таблицам, которые содержат
информацию, соответствующую этим исходным данным. Нужно обратить
особое внимание на команду JE после команды сканирования.
Существуют два случая, в которых управление передается этой
команде: байт в строке совпал с регистром AL и условие, задаваемое
префиксом REPNE, больше не выполняется; либо регистр CX достиг
нулевого значения без нахождения соответствующего числа в таблице.
В некоторых случаях создаются ситуации, исключающие появление
второго условия. Но в большинстве программ, необходимо учитывать
возможность неверных исходных данных. Программа перейдет на метку
FOUND после команды сканирования, если команда установила флаг нуля
(или равенства). Тем самым гарантируется, что сравнение найдено.
Если же регистр CX достиг нуля, последняя итерация сканирования
сбросила флаг нуля, показывая, что соответствия нет.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:01:36
Фиг. 4.24 Поиск в таблице Page 1-1
PAGE ,132
TITLE Фиг. 4.24 Поиск в таблице
0000 CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE
;--------------------------------------
; Поиск значения AL в таблице
;--------------------------------------
0000 8D 3E 000C R LEA DI, SCAN_TABLE ; Адрес таблицы
0004 B9 000B 90 MOV CX, SCAN_TABLE_LENGTH ; Длина таблицы
0008 F2/ AE REPNE SCASB ; Поиск
000A 74 00 JE FOUND ; Если равно, то значение найдено
; ... ; Иначе значение не найдено
000C FOUND:
;----- продолжение программы
000C 89 96 93 8A 85 8D 83 SCAN_TABLE DB 'ЙЦУКЕНГШЩЗХ'
98 99 87 95
= 000B SCAN_TABLE_LENGTH EQU $-SCAN_TABLE
0017 CODE ENDS
END
Фиг. 4.24 Сканирование таблицы
Последняя строковая команда - сравнение строк CMPS. Подобно
сканированию строки, это - команда сравнения. Подобно команде MOVS,
она работает с двумя операндами памяти. Команда CMPS сравнивает
строку по адресу DS:SI со строкой по адресу ES:DI, и соответственно
устанавливает флаги. Как и для команды SCAS, в данном случае
использовать префикс REP нельзя, а префиксы REPE и REPNE можно
использовать беспрепятственно.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:01:41
Фиг. 4.25 Сравнение строк Page 1-1
PAGE ,132
TITLE Фиг. 4.25 Сравнение строк
0000 CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE
;--------------------------------------
; Сравнивается 5-символьная строка с таблицей
; таких 5-символьных строк. Выход из программы
; если найдена искомая строка в таблице строк.
;--------------------------------------
0000 FIG4_25 PROC NEAR
0000 8D 36 001D R LEA SI, ARGUMENT ; Адрес строки
0004 8D 3E 0022 R LEA DI, COMPARE_TABLE ; Адрес таблицы
0008 BB 0000 MOV BX, 0 ; В BX cчетчик просмотренных строк
000B COMPARE_LOOP:
000B 56 PUSH SI ; Сохранение адреса строки
000C 57 PUSH DI ; Сохранение адреса таблицы
000D B9 0005 MOV CX, 5 ; Сравниваются 5 байт
0010 F3/ A6 REPE CMPS ARGUMENT,COMPARE_TABLE ; Сравнение
0012 5F POP DI ; Восстановление
0013 5E POP SI ; регистров
0014 74 06 JE FOUND ; Искомая строка найдена
0016 83 C7 05 ADD DI, 5 ; Сдвиг указателя на следующую
; строку в таблице
0019 43 INC BX ; Номер текущей строки в таблице
001A EB EF JMP COMPARE_LOOP ; Цикл
001C FOUND:
001C C3 RET
001D FIG4_25 ENDP
001D 41 42 43 44 45 ARGUMENT DB 'ABCDE'
0022 COMPARE_TABLE LABEL BYTE
0022 51 57 45 52 54 50 4F DB 'QWERT','POIUY','ASDFG','LKJHG'
49 55 59 41 53 44 46
47 4C 4B 4A 48 47
0036 5A 58 43 56 42 4D 4E DB 'ZXCVB','MNBVC','VWXYZ','ABCDE'
42 56 43 56 57 58 59
5A 41 42 43 44 45
004A CODE ENDS
END
Фиг. 4.25 Сравнение строк
Фиг. 4.25 демонстрирует пример использования команды CMPS.
Этот пример сравнивает пятисимвольную исходную строку с таблицей
строк символов. Программа пытается найти соответствие исходной
строки с элементом таблицы. Когда строка найдена, в регистре BX
нахолится индекс строки. В программе используется префикс REPE, так
что команда сравненния строк выполняется до тех пор, пока один из
символов аргумента не совпадает с символом таблицы. Если все пять
символов совпали, программа находит правильный элемент. Команда JE
("переход, если равно") проверяет результат команды CMPS. Если
сравнение завершилось из=за несоответствия символов, флаг нуля
показывает ненулевое состояние. Если же команда CMPS завершилась
потому, что счетчик CX стал нулевым, флаг нуля покажет совпадение и
произойдет переход на метку FOUND. Вы можете заметить, что в этом
примере отсутствуют некоторые необходимые детали, которые смогли бы
сделать его хорошей программой. Например, он никак не обрабатывает
случай, когда исходная строка не совпала ни с одним элементм
таблицы. Любой хороший программист скажет вам, что исключительные
ситуации нужно обрабатывать всегда.