Справочник по языку Ассемблера IBM PC

Команда cmps


Синтаксис команды cmps:


cmps адрес_приемника,адрес_источника


Здесь:

адрес_источника определяет цепочку-источник

в сегменте данных. Адрес цепочки должен быть заранее загружен в пару ds:esi/si;

адрес_приемника определяет цепочку-приемник. Цепочка должна находиться в дополнительном сегменте, и ее адрес должен быть заранее загружен в пару es:edi/di.

Алгоритм работы команды cmps заключается в последовательном выполнении вычитания (элемент цепочки-источника — элемент цепочки-получателя)

над очередными элементами обеих цепочек.


Принцип выполнения вычитания командой cmps аналогичен команде сравнения cmp. Она, так же, как и cmp, производит вычитание элементов, не записывая при этом результата, и устанавливает флаги zf, sf и of.


После выполнения вычитания очередных элементов цепочек командой cmps, индексные регистры esi/si и edi/di автоматически изменяются в соответствии со значением флага df на значение, равное размеру элемента сравниваемых цепочек.


Чтобы заставить команду cmps выполняться несколько раз, то есть производить последовательное сравнение элементов цепочек, необходимо перед командой cmps определить префикс повторения.


С командой cmps можно использовать префикс повторения repe/repz или repne/repnz:

repe или repz — если необходимо организовать сравнение до тех пор, пока не будет выполнено одно из двух условий:



достигнут конец цепочки (содержимое ecx/cx равно нулю);

в цепочках встретились разные элементы (флаг zf стал равен нулю);

repne или repnz — если нужно проводить сравнение до тех пор, пока:

не будет достигнут конец цепочки (содержимое ecx/cx равно нулю);

в цепочках встретились одинаковые элементы (флаг zf стал равен единице).

Таким образом, выбрав подходящий префикс, удобно использовать команду cmps для поиска одинаковых или различающихся элементов цепочек.


Выбор префикса определяется причиной, которая приводит к выходу из цикла. Таких причин может быть две для каждого из префиксов. Для определения конкретной причины наиболее подходящим является способ, использующий команду условного перехода jcxz. Ее работа заключается в анализе содержимого регистра ecx/cx, и если оно равно нулю, то управление передается на метку, указанную в качестве операнда jcxz. Так как в регистре ecx/cx содержится счетчик повторений для цепочечной команды, имеющей любой из префиксов повторения, то, анализируя ecx/cx, можно определить причину выхода из зацикливания цепочечной команды. Если значение в ecx/cx не равно нулю, то это означает, что выход произошел по причине совпадения либо несовпадения очередных элементов цепочек.



Существует возможность еще больше конкретизировать информацию о причине, приведшей к окончанию операции сравнения. Сделать это можно с помощью команд условной передачи управления (табл. 1 и 2).

Таблица 1. Сочетание команд условной передачи управления с результатами команды cmps (для чисел со знаком)

Причина прекращения операции сравнения Команда условного перехода, реализующая переход по этой причине
операнд_источник > операнд_приемник jg
операнд_источник = операнд_приемник je
операнд_источник <> операнд_приемник jne
операнд_источник < операнд_приемник jl
операнд_источник <= операнд_приемник jle
операнд_источник >= операнд_приемник jge
Таблица 2. Сочетание команд условной передачи управления с результатами команды cmps (для чисел без знака)

Причина прекращения операции сравнения Команда условного перехода, реализующая переход по этой причине
операнд_источник > операнд_приемник ja
операнд_источник = операнд_приемник je
операнд_источник <> операнд_приемник jne
операнд_источник < операнд_приемник jb
операнд_источник <= операнд_приемник jbe
операнд_источник >= операнд_приемник jae
Как определить местоположение очередных совпавших или не совпавших элементов в цепочках?

Вспомните, что после каждой итерации цепочечная команда автоматически осуществляет инкремент/декремент значения адреса в соответствующих индексных регистрах. Поэтому после выхода из цикла в этих регистрах будут находиться адреса элементов, находящихся в цепочке после (!) элементов, которые послужили причиной выхода из цикла.

Для получения истинного адреса этих элементов необходимо скорректировать содержимое индексных регистров, увеличив либо уменьшив значение в них на длину элемента цепочки.

В качестве примера рассмотрим программу из листинга 2, которая сравнивает две строки, находящиеся в одном сегменте. Используется команда cmps. Префикс повторения - repe.

 Листинг 2. Сравнение двух строк командой cmps <1> ;prg_11_2.asm <2> MODEL       small <3> STACK       256 <4> .data <5> match       db      0ah,0dh,'Строки совпадают.','$' <6> failed      db      0ah,0dh,'Строки не совпадают','$' <7> string1     db      '0123456789',0ah,0dh,'$';исследуемые строки <8> string2     db      '0123406789','$' <9> .code <10> ASSUME     ds:@data,es:@data       ;привязка DS и ES к сегменту данных <11> main: <12>    mov     ax,@data        ;загрузка сегментных регистров <13>    mov     ds,ax <14>    mov     es,ax   ;настройка ES на DS <15> ;вывод на экран исходных строк string1 и string2 <16>    mov     ah,09h <17>    lea     dx,string1 <18>    int     21h <19>    lea     dx,string2 <20>    int     21h <21> ;сброс флага DF — сравнение в направлении возрастания  адресов <22>    cld <23>    lea     si,string1      ;загрузка в si смещения string1 <24>    lea     di,string2      ;загрузка в di смещения string2 <25>    mov     cx,10   ;длина строки для префикса repe <26> ;сравнение строк (пока сравниваемые элементы строк равны) <27> ;выход при обнаружении не совпавшего элемента <28> cycl: <29>    repe    cmps    string1,string2 <30>    jcxz    equal   ;cx=0, то есть строки совпадают <31>    jne     not_match       ;если не равны — переход на not_match <32> equal:             ;иначе, если совпадают, то <33>    mov     ah,09h  ;вывод сообщения <34>    lea     dx,match <35>    int     21h <36>    jmp     exit    ;выход <37> not_match:         ;не совпали <38>    mov     ah,09h <39>    lea     dx,failed <40>    int     21h     ;вывод сообщения <41> ;теперь, чтобы обработать не совпавший элемент в  строке, необходимо уменьшить значения регистров si и di <42>    dec     si <43>    dec     di <44> ;сейчас в ds:si и es:di адреса несовпавших элементов <45> ;здесь вставить код по обработке несовпавшего элемента <46> ;после этого продолжить поиск в строке: <47>    inc     si <48>    inc     di <49>    jmp     cycl <50> exit:      ;выход <51>    mov     ax,4c00h <52>    int     21h <53> end        main    ;конец программы

Программа достаточно прозрачна, только два момента, на мой взгляд, требуют пояснения:

во-первых, строки 42 и 43, в которых мы скорректировали адреса очередных элементов для получения адресов несовпавших элементов. Вы должны понимать, что если сравниваются цепочки с элементами слов или двойных слов, то корректировать содержимое esi/si и edi/di нужно на 2 и 4 байта соответственно;

во-вторых, строки 47–49. Смысл их в том, что для просмотра оставшейся части строк необходимо установить указатели на следующие элементы строк за последними несовпавшими. После этого можно повторить весь процесс просмотра и обработки несовпавших элементов в оставшихся частях строк. 


Содержание раздела