Я пытаюсь перевернуть строку в своем классе языка ассемблера. Я считаю, что у меня правильный код, но на выходе получается только «а». Вот код:
; Reverses an input string of at least 10 characters
; Author: Nathan Smith
; Created: 10/26/2018
; Revisions:
; Date: Modified by:
INCLUDE Irvine32.inc
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
.data
myString BYTE "abcdefghij", 0 ; original string
temp BYTE ? ; temporary string holder
.code
main PROC
mov esi, SIZEOF myString ; source index register
mov ecx, SIZEOF myString ; loop counter
movzx eax, myString ; moves string to temp holder
mov temp, al
mov edi, 0 ; destination index register
L1:
mov al, temp[esi] ; moves last letter to al
mov myString[edi], al ; moves letter from al to myString
dec esi ; decreases pointer by 1
inc edi ; increases destination pointer by 1
loop L1 ; repeat for length of string
mov edx, OFFSET myString
call WriteString
INVOKE ExitProcess,0
main ENDP
END main
Я не уверен, что происходит.
да, но у ассемблера нет термина string
. Может, лучше вообще не объяснять. Дело в том, что имя переменной не может указывать на что-то другое, кроме своего исходного места. Это не C или около того.
Даже если я перейду на mov al, myString
, он сделает то же самое.
@ndsmith Перепиши все по старинке
Длина строки должна учитывать нулевую индексацию, поэтому;
mov esi, SIZEOF myString - 1 ; Should equal 8
mov ecx, SIZEOF myString ; Should equal 9
Завершающий символ 0x0 НУЛЕВОЙ необходимо записать в конец темп. Чтобы хотя бы немного оптимизировать, запись 4 NULL работает, поскольку EDI - это только 32-битный регистр.
xor edi, edi
mov temp[ecx],edi ; Writing 4 chars
; Instead of
mov BYTE temp[ecx], 0
Единственное, что нужно изменить в вашем цикле:
@@:
mov al, myString [edi] ; Read char from source
mov temp[esi], al ; and write to destination
dec esi
inc edi
loop @B
Что происходило с вашей программой, так это то, что
movzx eax, myString
mov temp, al
Перемещал первый символ источника в первую позицию назначения, и поскольку вы не учли нулевую индексацию, завершающий символ из источника был следующей записью в темп.
Если вы используете другой регистр для счетчика, который необходимо обнулить, эффективен mov temp[ecx], dl
.
Код @PeterCordes OP имеет огромное количество раздувания, я старался не отклоняться далеко от цели вопроса. Я сделал пример только для себя, который вошел в 23 байта против 57 оригинального сообщения.
Ага. Но поскольку вы упоминали об изменениях, вам не нужно создавать хранилище двойных слов, которое включает 3 байта после конца того, что вы в противном случае написали бы. В любом случае, вы забыли еще одну серьезную ошибку: temp BYTE ?
OP имеет только 1-байтовый буфер для места назначения.
Я думаю, вы путаете указатель на строку и строку. Вы выделили отдельный байт для
temp
, но читаете из этого места в памяти, как если бы данных было больше 1.movzx eax, myString
перемещает первый байтmyString
в eax, а ноль расширяет значение, чтобы заполнить EAX.