Сравнение строк

Последнее обновление: 03.07.2023

Для сравнения строк из различных типов чисел применяются инструкции

  • cmpsb: сравнивает строку байтов

  • cmpsw: сравнивает строку из слов

  • cmpsd: сравнивает строку из двойных слов

  • cmpsq: сравнивает строку из четверных слов

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

Вместе с этой инструкцией можно использовать ряд префиксов:

  • Префикс repe указывает повторять операцию до тех пор, пока сравнение равно, или до количества раз, указанного RCX (в основном применяется для сравнений символьных строк).

  • Префикс repne повторяет операцию, пока сравнение не равно, или до количества раз, указанного RCX

Без применения этих префиксов инструкции cmps вычитают значение в RDI из значения в RSI и обновляет флаги в соответствии с результатом. После сравнения двух чисел cmps увеличивает или уменьшает регистры RSI и RDI на 1, 2, 4 или 8 (для cmpsb, cmpsw, cmpsd и cmpsq соответственно). cmps увеличивает регистры RSI и RDI, если флаг направления сброшен, и уменьшает их, если флаг установлен. Например, сравненим равные по длине массивы:

.data
nums1 word 10, 11, 12, 13, 14, 15, 16, 17
nums2 word 10, 11, 12, 13, 14, 15, 16, 17
.code
main proc
    lea rsi, nums1
    lea rdi, nums2
    mov rcx, 8     ; 8 слов
    repe cmpsw     ; сравниваем слова
    jz equal
    mov eax, 0      ; если строки не равны
    jmp exit
equal:
    mov eax, 1      ; если строки равны
exit:
    ret
main endp
end

Здесь сравниваем два массива чисел. Если они равны, помещаем в EAX число 1, если не равны - число 0.

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

В этом случае в регистр RCX помещается длина наименьшей строки. Далее обе строки сравниваются как и вобщем случае. И если они равны, сравниваются их длины.

Пример сравнения двух строк:

.data
str1 byte "Hello World", 0
str1_len = $ - str1         ; длина первой строки 
str2 byte "Hello World", 0
str2_len = $ - str2         ; длина второй строки
.code
main proc
    lea rsi, str1
    lea rdi, str2
    mov rcx, str1_len
    cmp rcx, str2_len   ; сравниваем длины строк
    jbe compare         ; если длина num1 равна или меньше

    mov rcx, str2_len   ; если длина num2 меньше

compare:
    repe cmpsb      ; сравниваем байты
    jnz notequal    ; если не равны

    mov rcx, str1_len
    cmp rcx, str2_len   ; если равны, сравниваем длины строк
    jnz notequal
    mov eax, 1          ; если строки равны
    jmp exit
notequal:
    mov eax, 0          ; если строки не равны
exit:
    ret
main endp
end

Строки символов обычно сравниваются в алфавитном порядке. Поскольку символы фактически представлены их числовами кодами, то сравнение символов выливается в сравнение их числовых кодов (в данном случае для простоты считаем, что символы в разных регистрах - это разные символы).

Сравнение больших чисел

Инструкции cmps удобны для сравнения очень больших чисел, которые выходят за пределы 64 бит. Например:

.data
num1 qword 0000000000000005h, ; младшие 64 бита
           0000000000000002h  ; старшие 64 бита

num2 qword 0000000000000005h, ; младшие 64 бита
           0000000000000002h  ; старшие 64 бита
.code
main proc

    lea rsi, num1[8]    ; загружаем адрес старших 64 битов
    lea rdi, num2[8]    ; загружаем адрес старших 64 битов
    mov rcx, 2          ; сравниваем 2 qword - младшие и старшие 64 бита
    std                 ; устанавливаем обратный порядок сравнения
    repe cmpsq          ; сравниваем qword
    cld                 ; после сравнения сбрасываем флаг направления
    jnz notequal
    mov eax, 1          ; если строки равны
    jmp exit
notequal:
    mov eax, 0          ; если строки не равны
exit:
    ret
main endp
end

Здесь сравниваются два 128-разрядных числа. Каждое число фактически представляет массив из двух чисел qword - младших и старших 64 битов. Общий алгоритм сравнения подобных чисел заключается в последовательном сравнении их соответствующих 64 разрядов. Если старшие 64 разряда не равны, то числа уже не равны. Если старшие 64 разряда равны, то сравниваются следующие 64 разряда и так далее.

Поскольку вначале массива, который представляет 128-разрядное число располагается младшие 64 бит, то нам надо сравнивать с конца. Для этого загражаем в регистры RSI и RDI старшие 64 разряды и устанавливаем флаг направления с помощью инструкции std. Для сравнения каждой 64-разрядной части применяем инструкцию cmpsq

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850