2016-11-06 2 views
-1

Мое назначение - реализовать функцию в сборке, которая будет делать следующее: цикл через последовательность символов и свопинг их таким образом, чтобы конечный результат был исходной строкой в ​​обратном порядке (100 баллов) Подсказка: соберите строку от пользователя как C-строку, затем передайте ее функции сборки вместе с количеством символов, введенных пользователем. Чтобы узнать количество символов, используйте функцию strlen().Сборка: циклическая последовательность символов и их замена

Я написал как C++, так и сборки, и он отлично работает для расширения: например, если я ввожу 12345, то вывод правильно показан как 54321, но если вы перейдете более чем на 5 символов: стартовый старт будет неправильным: например, если я ввожу 123456, выход: 653241. Я буду очень признателен всем, кто может указать, где моя ошибка состоит в том:

.code 

_reverse PROC 
    push ebp  
    mov ebp,esp ;stack pointer to ebp 

    mov ebx,[ebp+8]  ; address of first array element 
    mov ecx,[ebp+12] ; the number of elemets in array 
    mov eax,ebx 
    mov ebp,0   ;move 0 to base pointer 
    mov edx,0  ; set data register to 0 
    mov edi,0 

Setup: 

    mov esi , ecx 
    shr ecx,1 
    add ecx,edx 
    dec esi 

reverse: 

    cmp ebp , ecx 
    je allDone 

    mov edx, eax 
    add eax , edi 
    add edx , esi 

Swap: 
    mov bl, [edx] 
    mov bh, [eax] 

    mov [edx],bh 
    mov [eax],bl 

    inc edi 
    dec esi 

    cmp edi, esi 
    je allDone 

    inc ebp 
    jmp reverse 

allDone: 
    pop ebp    ; pop ebp out of stack 
    ret     ; retunr the value of eax 
_reverse ENDP 

END 

и вот мой C++ код:

#include<iostream> 
#include <string> 

using namespace std; 
extern"C" 
char reverse(char*, int); 

int main() 
{ 
    char str[64] = {NULL}; 
    int lenght; 

    cout << " Please Enter the text you want to reverse:"; 
    cin >> str; 
    lenght = strlen(str); 

    reverse(str, lenght); 

    cout << " the reversed of the input is: " << str << endl; 

    } 
+1

Не заметили никаких реальных ошибок, просто действительно странные вещи. Если вы собираетесь использовать EBP в качестве реестра общего назначения, вы должны оставить материал 'mov ebp, esp'. (И просто получить доступ к вашим аргументам со смещением от ESP). Такие комментарии, как 'set data register to 0', бесполезны. Было бы полезно описать, для чего используется ваша функция EDX. 'mov eax, ebx' в верхней части функции кажется бесполезным, почему бы просто не загружать в EAX? Единственное использование EBX в остальной части функции - положить байты в BL и BH. –

+0

Одна ошибка заключается в том, что вы должны сохранять/восстанавливать EBX, как вы делаете EBP, потому что он сохраняется во всех обычных 32-битных соглашениях. Вероятно, у вас, вероятно, есть еще одна ошибка, так как переход на значение EBX вашего вызывающего абонента, вероятно, не приведет к поведению, которое вы видите. Вы должны сделать один шаг через свой код в отладчике, чтобы узнать, что он делает. –

+0

Большое спасибо Мистер Кордес за ваши замечательные и конструктивные комментарии, я сожалею, что загрузил такой плохой код без комментариев вообще, я был настолько расстроен своим кодом, что забыл посмотреть на мои глупые комментарии. – ArashDe

ответ

3

Вы не комментировал свой код, так ИДК, что именно вы пытаетесь но похоже, что вы вручную выполняете индексирование массива с помощью MOV/ADD вместо использования режима адресации, например, [eax + edi].

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

mov edx, eax   ; EAX holds a pointer to the start of array, read every iter 
    add eax , edi  ; modify the start of the array!!! 
    add edx , esi 

Swap: 
    inc edi 
    dec esi 

EAX растет на EDI каждый шаг, а EDI увеличивается линейно. Поэтому EAX увеличивается геометрически (интеграл (x * dx) = x^2).

Одноступенчатое это в отладчике должно было легко найти это.


Кстати, нормальный способ сделать это, чтобы пройти один указатель вверх, один указатель вниз, и выпадают из цикла, когда они пересекают. Тогда вам не нужен отдельный счетчик, только cmp/ja. (Не проверяйте JNE или JE, потому что они могут пересекать друг друга, даже не будучи равными.)

+0

Я использовал режим адресации, как вы мне сказали, и геометрически увеличил приращение EAX. Также использовались указатели для сравнения вместо индекса, и, поскольку я не знал, что они могут пересекать друг друга, даже не будучи равным, я использовал JA commend, как вы предложили, и он отлично работал – ArashDe

+0

@ArashDe: рад, что это помогло. Вы должны установить флажок под стрелками для голосования, чтобы отметить этот ответ как принятый, если вам кажется, что он отвечает на вопрос. –

0

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

mov ebp,0   ;move 0 to base pointer 

Это похоже на счетчик циклов (комментарий бесполезен или даже хуже); Я предполагаю, что идея состояла в том, чтобы обменять length/2 элементов, которые отлично подходят. СОВЕТ Я просто сравню указатели/индексы и выйду, как только они столкнутся.

mov edx,0  ; set data register to 0 
... 
add ecx,edx 
mov edx, eax 

Бесполезный и вводящий в заблуждение.

mov edi,0 
mov esi , ecx 
dec esi 

Похоже, что индексы начинаются/заканчиваются. ОК. СОВЕТ Я бы пошел с указателями на начало/конец строки; но также работают индексы

cmp ebp , ecx 
je allDone 

Выход, если длина/2 итерации. ОК.

mov edx, eax 
add eax , edi 
add edx , esi 

eax и edx точка текущих символов для замены. Почти нормально, но этот clobbers eax!Каждая итерация цикла после второго будет использовать неверные указатели! Это и послужило причиной вашей проблемы в первую очередь. Это не случилось бы, если бы вы использовали указатели вместо индексов, или если бы вы использовали смещение адресации [eax+edi]/[eax+esi]

... 

Своп часть OK

cmp edi, esi 
je allDone 

Второе условие выхода, на этот раз по сравнению для столкновение индекса! Обычно одного условия выхода должно быть достаточно; несколько условий выхода обычно либо избыточны, либо намекают на некоторые недостатки алгоритма. Сравнение равенств недостаточно - индексы могут идти от edi<esi до edi>esi во время одиночной итерации.

Смежные вопросы