String 反转用户在汇编语言中给定的字符串

String 反转用户在汇编语言中给定的字符串,string,assembly,character,reverse,String,Assembly,Character,Reverse,我现在正在用汇编语言编写一个程序,用户可以输入他们喜欢的任何单词,然后程序会将其反转。因此,如果用户输入HELLO,程序将输出OLLEH 我决定实现的算法是首先获取字符串的长度并将其存储在length中。然后,我将使用长度在给定字符串中向后遍历,并将每个字符存储在一个新的内存位置REVERSE。我测试了我的程序好几次,但它只输出一个字符。我尝试了几个单词,注意到字符总是输出的是字符串的第二个字符,所以我不确定它是否能够反转单词 我是否遗漏了什么,或者我错误地实现了一个代码块 注意:以.exe格式

我现在正在用汇编语言编写一个程序,用户可以输入他们喜欢的任何单词,然后程序会将其反转。因此,如果用户输入HELLO,程序将输出OLLEH

我决定实现的算法是首先获取字符串的长度并将其存储在
length
中。然后,我将使用长度在给定字符串中向后遍历,并将每个字符存储在一个新的内存位置
REVERSE
。我测试了我的程序好几次,但它只输出一个字符。我尝试了几个单词,注意到字符总是输出的是字符串的第二个字符,所以我不确定它是否能够反转单词

我是否遗漏了什么,或者我错误地实现了一个代码块

注意:以
.exe
格式运行代码时,会使用
GET_字符串[end]5

以下是我目前正在处理的代码:

%include "io.inc"
section .data
string dd 0x00
end dd 0x00
REVERSE dd 0x00
length db 0

section .text
global CMAIN
CMAIN:
    ;write your code here
    
    PRINT_STRING "Please enter a string: "
    GET_STRING [string], 10
    
    lea esi, [string]
    lea edi, [REVERSE]
    lea ecx, [length]
    
L1:
    mov al, [esi]
    cmp al, 0
    JE FINISH
    JNE INCREMENT
    inc esi
    jmp L1

INCREMENT:
    inc byte[length]
    inc esi
    jmp L1
    

    FINISH: 
    L2:
;points to the current index of the string (i.e. if Hello,it will first point at 'o' which is 5
    mov al, [ecx] 
    cmp cl, 0  ;checks if length == 0
    JE DONE
    JNE DECREMENT
    dec ecx
    jmp L2

DECREMENT:
    mov byte[edi], al ;adds a character from [string]
    dec ecx
    jmp L2
    
DONE:
    PRINT_STRING REVERSE
    GET_STRING[end], 5
    xor eax, eax
    ret
如果GET_字符串给您一个以零结尾的字符串,那么您的L1部分将找到该字符串的长度

这是删除冗余代码后剩下的内容:

    lea   esi, [string]
L1:
    mov   al, [esi]
    cmp   al, 0
    je    FINISH
    inc   byte [length]
    inc   esi
    jmp   L1
FINISH:
但是在第二语言部分

  • 您正在使用长度变量的地址,就好像它是字符串本身的地址一样
  • 您正在从未使用长度加载的寄存器中检查长度==0
在L2部分的开始处,
ESI
寄存器仍然指向终止零。因此,必须先递减,然后提取并存储字符

当然,如果长度变量包含0,则不能复制任何字符。所以首先检查这个条件

    lea   edi, [REVERSE]
    mov   cl, [length]
    test  cl, cl
    jz    DONE
L2:
    dec   esi             ; Decrement
    mov   al, [esi]       ; Fetch
    mov   [edi], al       ; Store
    inc   edi
    dec   cl              ; 1 more character done
    jnz   L2
DONE:
    mov   [edi], cl       ; CL=0 at this point, now zero-terminating the result
如果保留当前数据定义,则输入的字符不要超过3个。dword
dd
仅允许3个字符和1个以零结尾的字符。
或者扩大缓冲区:

string  db 11 dup (0)        ; GET_STRING [string], 10
end     db  6 dup (0)        ; GET_STRING [end], 5
REVERSE db 11 dup (0)
length  db 0

下面是一个不使用基于内存的长度变量的版本。字符串的长度存储在
ECX

    lea   edi, [REVERSE]
    lea   esi, [string]
L1:
    mov   al, [esi]
    inc   esi
    cmp   al, 0
    jne   L1
    lea   ecx, [esi - 1 - String]
    jecxz DONE
; ESI points behind the terminating zero, the fetch uses a -2 offset (avoiding address stall)
L2:
    mov   al, [esi - 2]   ; Fetch
    mov   [edi], al       ; Store
    dec   esi
    inc   edi
    dec   ecx             ; 1 more character done
    jnz   L2
DONE:
    mov   [edi], cl       ; CL=0 at this point, now zero-terminating the result

感谢您投入工作,给出详细的问题描述。对代码的一些注释,表明您认为代码正在做什么,也可能会有所帮助。没有他们,我只能看到它的作用,很难说这是否符合你的意图。谢谢你指出这一点!我编辑了我的帖子,并在代码中添加了评论。我希望我的评论能够解释我现在试图实现的内容。JE FINISH和JNE INCREMENT涵盖了这两种可能性,因此无法访问它们后面的
inc esi
/
jmp L1
。您应该能够通过删除它来简化逻辑,只需将
INCREMENT
案例放入该块即可。(事实上,您应该能够将循环安排为只有一个总分支,底部是一个条件分支。)在内存中设置
长度也没有意义;你有足够的寄存器。另外,希望输入函数返回一个长度……而且,
dd0
只占用4字节的空间,因此用户输入的任何长度超过该长度的内容都将重叠到您在另一个标签后保留的空间中。
io.inc
是SASM中所需的包。SASM目前是我解决问题所需的汇编程序。我仍在尝试将大家现在分享的内容纳入我的答案,因为我仍然很难用另一种语言迁移。谢谢你向我解释我出错的地方。你的解释真的很有帮助,让我明白了寄存器的指向。这真的让事情更清楚了。
    lea   edi, [REVERSE]
    lea   esi, [string]
L1:
    mov   al, [esi]
    inc   esi
    cmp   al, 0
    jne   L1
    lea   ecx, [esi - 1 - String]
    jecxz DONE
; ESI points behind the terminating zero, the fetch uses a -2 offset (avoiding address stall)
L2:
    mov   al, [esi - 2]   ; Fetch
    mov   [edi], al       ; Store
    dec   esi
    inc   edi
    dec   ecx             ; 1 more character done
    jnz   L2
DONE:
    mov   [edi], cl       ; CL=0 at this point, now zero-terminating the result