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

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

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

  • 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, если флаг направления сброшен, и уменьшает их, если флаг установлен. Например, сравненим равные по длине массивы:

.globl _start

.data
nums1: .word 10, 11, 12, 13, 14, 15, 16, 17
nums2: .word 10, 11, 12, 13, 14, 15, 16, 17
.text
_start:
    movq $nums1, %rsi
    movq $nums2, %rdi
    movq $8, %rcx     # 8 слов
    repe cmpsw        # сравниваем слова
    jz equal        # если строки равны, переход к метке equal
    movq $2, %rdi      # если строки не равны, RDI = 2
    jmp exit
equal:
    movq $4, %rdi      # если строки равны, RDI = 4
exit:
    movq $60, %rax
    syscall

Здесь сравниваем два массива чисел. Если они равны, помещаем в %rdi число 4, если не равны - число 2.

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

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

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

.globl _start

.data
str1: .ascii "Hello World"
str1_len = . - str1         # длина первой строки 
str2: .ascii "Hello World"
str2_len = . - str2         # длина второй строки
.text
_start:
    movq $str1, %rsi
    movq $str2, %rdi
    movq $str1_len, %rcx
    cmpq $str2_len, %rcx   # сравниваем длины строк
    jbe compare             # если длина str1 равна или меньше

    movq $str2_len, %rcx   # если длина str2 меньше

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

    movq $str1_len, %rcx
    cmpq $str2_len, %rcx   # если равны, сравниваем длины строк
    jnz notequal
    movq $1, %rdi          # если строки равны
    jmp exit
notequal:
    movq $0, %rdi          # если строки не равны
exit:
    movq $60, %rax
    syscall

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

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