MASM Почему при уменьшении регистра не удается найти следующее значение в массиве?

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

['A']['B']['C']['D']['A']

ebx изменится с «A» -> «B», но edi не изменится с «A» -> «D»

Почему ebx меняет символы, а edi вычитает только 1 из значения регистра? Что я могу сделать, чтобы изменить значение символа edi? Спасибо!

Код С++: (на всякий случай)

#include <iostream>
#include <cstring>
#include <sstream>

using namespace std;

extern"C"
{
char stringClean(char *, int);
char isPalindrome(char *, int);
}

int main()
{
int pal = 0;
const int SIZE = 30;
string candidate = "";
char strArray[SIZE] = { '\0' };

cout << "enter a string to be tested: ";
getline(cin, candidate);


int j = 0;
for (int i = 0; i < candidate.length(); i++)        //getting rid of garbage before entering into array
{
    if (candidate[i] <= 'Z' && candidate[i] >= 'A' || candidate[i] <= 'z' && candidate[i] >= 'a')
    {
        strArray[j] = candidate[i];
        j++;
    }
}

if (int pleaseWork = stringClean(strArray, SIZE) == 0)
    pal = isPalindrome(strArray, SIZE);

if (pal == 1)
    cout << "Your string is a palindrome!" << endl;
else
    cout << "Your string is NOT a palindrome!" << endl;

system("pause");
return 0;
}

масм код:

.686
.model flat
.code

_isPalindrome PROC ; named _test because C automatically prepends an underscode, it is needed to interoperate
    push ebp
    mov ebp,esp ; stack pointer to ebp

    mov ebx,[ebp+8] ; address of first array element
    mov ecx,[ebp+12] ; number of elements in array
    mov ebp,0
    mov edx,0
    mov eax,0
    push edi    ;save this
    push ebx    ;save this

    mov edi, ebx    ;make a copy of first element in array
    add edi, 29     ;move SIZE-1 (30 - 1 = 29) elements down to, HOPEFULLY, the last element in array

    mov bl, [ebx]
    mov dl, [edi]

    cmp dl, 0           ;checks if last element is null
    je nextElement      ;if null, find next
    jne Comparison      ;else, start comparing at Comparison:

nextElement:
    dec edi             ;finds next element
    mov dl, [edi]       ;move next element into lower edx
    cmp dl, 0           ;checks if new element is mull
    je nextElement      ;if null, find next
    jne Comparison      ;else, start comparing at Comparison:

Comparison:
    cmp bl,dl           ;compares first element and last REAL element
    je testNext         ;jump to textNext: for further testing

    mov eax,1           ;returns 1 (false) because the test failed
    jne allDone         ;jump to allDoneNo because it's not a palindrome

testNext:
    dec edi     ;finds last good element -1 --------THIS ISN'T DOING the right thing
    inc ebx             ;finds second element

    cmp ebx, edi        ;checks if elements are equal because that has tested all elements
    je allDone          

    ;mov bl,[ebx]       ;move incremented ebx into bl
    ;mov dl,[edi]       ;move decremented edi into dl
    jmp Comparison      ;compare newly acquired elements



allDone:
    xor eax, eax
    mov ebp, eax

    pop edi
    pop edx
    pop ebp
    ret
_isPalindrome ENDP

END 

person dr nips    schedule 03.12.2015    source источник
comment
Вы прошли через это с отладчиком? У Microsoft есть хороший отладчик в Visual Studio, но OllyDbg тоже очень хорош.   -  person Michael Petch    schedule 03.12.2015
comment
У вас есть некоторые ошибки, такие как mov eax, 1 для возвращаемого значения, но затем всегда очищается eax перед возвратом в allDone. Кроме того, не пишите jcc label / label:. Просто позвольте выполнению провалиться, так как оно будет независимо от того, взята ветвь или нет. Обычно после сравнения вам нужен только один jcc, если только у вас нет одного jg и одного jge или чего-то подобного. Но не jg / jle. Либо провалитесь без прыжка, либо используйте безусловную jmp для второго, если вам нужно прыгнуть куда-то еще. Как только вы разобрались со своим дизайном, вы можете попробовать. переставить, чтобы сэкономить на ветках.   -  person Peter Cordes    schedule 03.12.2015
comment
Я обнаружил, что перемещаю значение регистра в нижнюю часть того же регистра. =р   -  person dr nips    schedule 03.12.2015


Ответы (1)


Я не тестировал ваш код, но, глядя на него, я заметил некоторые возможные проблемы.

Почему ebx меняет символы

Кажется, что так, но это не то, чего вы пытались достичь. Вы закомментировали строки, читающие символы из памяти/массива после начальной фазы (см. ниже). Так что на самом деле вы изменили символ в EBX, но не так, как ожидали (и якобы хотели). С помощью INC EBX вы увеличили значение символа с «A» (65dec) до «B» (66dec). То, что «B» также является вторым символом строки, является просто совпадением. Попробуйте изменить строку с ABCDA на ARRCD или что-то в этом роде, и вы все равно получите «B» во втором раунде. Так что EBX действительно меняется.

...
;mov bl,[ebx]       ;move incremented ebx into bl
;mov dl,[edi]       ;move decremented edi into dl
jmp Comparison      ;compare newly acquired elements
...

но edi вычитает только 1 из значения регистра? Что я могу сделать, чтобы изменить значение символа edi?

Да. Это то, что делает ваш код, и это правильно. Раскомментируйте приведенную выше строку, содержащую [edi], и символ, на который указывает EDI, будет загружен в младший байт EDX = DL.

Проблема с вашим кодом заключается в том, что вы используете EBX как указатель и (char) значение. Загрузка следующего символа в EBX уничтожит указатель, и ваша программа, скорее всего, рухнет с ACCESS_VIOLATION на следующей итерации или продемонстрирует случайное поведение, которое будет трудно отладить.

Отделите указатели от значений, как вы сделали с EDI/EDX (EDI=указатель на char, EDX(DL)=значение char.

Другая проблема: ваш код будет работать только для строк нечетной длины.

testNext:
    dec edi         ; !!!
    inc ebx         ; !!!
cmp ebx, edi        ; checks if elements are equal because that has tested all elements
je allDone  

Итак, вы увеличиваете и уменьшаете (должны быть) указатели, а затем сравниваете их. Теперь рассмотрим этот случай строки четной длины:

  ABBA
  ^  ^   (EBX(first) and EDI(second))
=> dec both =>
  ABBA
   ^^    (EBX(first) and EDI(second))
=> dec both =>
  ABBA
   ^^    (EDI(first) and EBX(second))
=> dec both =>
  ABBA
  ^  ^   (EDI(first) and EBX(second))
=> dec both =>
  ABBA
 ^    ^  (EDI(first) and EBX(second)) 
... 

=> Проблема! Не завершается, условие EBX=EDI никогда не будет выполнено* Возможное решение: добавьте A (выше = больше для значений без знака) к переходу

...
cmp ebx, edi
jae allDone
person zx485    schedule 03.12.2015