4.8.4. Команды сканирования и сравнения

Две оставшиеся строковые команды используются в программах для сравнения строковой информации. Первая из них - команда, сканирование строки 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:00:49
Фиг. 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:00:49
Фиг. 4.25 Сравнение строк                                       Page  1-1
                         PAGE     ,132
                         TITLE    Фиг. 4.25 Сравнение строк
0000                     CODE     SEGMENT
                         ASSUME   CS:CODE,DS:CODE,ES:CODE
                         ;--------------------------------------
                         ; Сравнивается 5-символьная строка с таблицей
                         ; таких 5-символьных строк. Выход из программы
                         ; если найдена искомая строка в таблице строк.
                         ;--------------------------------------
000                      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. Вы можете заметить, что в этом примере отсутствуют некоторые необходимые детали, которые смогли бы сделать его хорошей программой. Например, он никак не обрабатывает случай, когда исходная строка не совпала ни с одним элементм таблицы. Любой хороший программист скажет вам, что исключительные ситуации нужно обрабатывать всегда.