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