assembly - Tasm:尝试将一个字符串以相反的顺序复制到另一个字符串并使用字符串操作显示它
问题描述
嗨,我正在尝试逐个字符地从用户获取字符串,然后将该字符串的反转存储在未初始化的变量中。在我想显示那个未初始化的变量之后。我知道还有其他方法可以做到这一点,但我想使用字符串操作来做到这一点,我认为 std 指令可以用来以相反的顺序遍历字符串。我知道 cld 用于设置从左到右的顺序。我还检查了教科书,它说在使用 std 和 popf 之前使用 pushf 。如果是这种情况,那么 push 和 pop 应该放在哪里。
INCLUDE PCMAC.INC
.MODEL SMALL
.386
.STACK 128
;================================================
.DATA
prompt1 DB 13, 10,'Enter a character(Press ENTER to end Expression): $'
prompt2 DB 'Are you done ?: $'
prompt3 DB 13, 10,'Not valid choice try again', 13, 10,'$'
userExp DB 50 DUP (?)
bwUserExp DB 50 DUP (?)
validity DB 'Invalid$','Valid$'
;================================================
.CODE
EXTRN PutStr : NEAR, GetCh : NEAR, PutCh : NEAR
Main PROC NEAR
mov ax, @DATA
mov ds, ax
mov es, ax
xor bx, bx ;Clears bx register
xor cx, cx ;Clears cx register
DispPrompt: _PutStr prompt1 ;Displays prompt1 to screen
GetEXP: _GetCh al ;Gets character from user
cmp al, 13 ;Compares character
;to Carriage return
je LoadUserExp ;If equal to the carriage
;return user jumps to
;LoadUserExp
cmp al, 97 ;Compares character to a
jge AddtoExp ;If equal or greater than
;a user jumps to AddtoExp
cmp al, 122 ;Compares character to z
jle AddtoExp ;If equal or greater than
;a user jumps to AddtoExp
jmp GetEXP ;Jumps to GetEXP if character
;is not any of the matching
;characters
AddtoExp: mov userExp + bx, al ;Adds character from
;al to userExp array
inc bx ;increments bx to
;increment the position
;in the array
jmp GetEXP ;Jumps to GetEXP
LoadUserExp:
mov si, OFFSET userExp ;Loads userExp into si
mov di, OFFSET bwUserExp ;Loads bwUserExp into di
std ;Tells the program to
;go from Right to the Left
mov cx, bx ;Moves bx (the size of the array) into cx
rep movsb ;Moves the contents of si into di
DispLoop:
mov cx, bx ;Moves bx (the size of the array) into cx
xor bx, bx ;Clears the bx register
DisplayExp: mov al, bwUserExp + bx ;Moves the character
;in position bx into al
_PutCh al ;Displays the value of
;al to the screen
inc bx ;increments bx to increment
;the position in the array
dec cx ;Decrements cx
jcxz done ;Jumps to done if
;cx is zero
jmp DisplayExp ;Jumps to DisplayExp
; if cx is not zero
done: mov ax, 4c00h
int 21h
Main ENDP
;================================================
END Main
解决方案
您的代码显示了几个问题,但让我们关注“字符串”指令。
关于 DF(方向标志)
将寄存器cld
中的 DF 设置FLAGS
为零。将std
DF 设置为 1。
建议的目的pushf
是保留原始DF
值,即pushf + popf
封闭对应该围绕您的整个操作,您正在修改 DF,以保留原始值,并且如果您的代码是唯一运行的代码,并且没有被调用外部函数,您可以决定不关心原始 DF。
在 x86 调用约定中,通常决定 DF 预计为零,那么您不需要保留原始值,您只需在代码的每一部分之后清除 DF,这确实需要 DF=1,然后再调用一些其他子程序。这种约定通常效果很好,因为只有在极少数情况下才需要 DF=1。
即将movs
反转字符串
movs[b/w/d]
将从 加载值并将其[ds:si]
存储到[es:di]
,然后通过添加(当 DF=0 时)元素大小或减去(DF=1)元素大小来调整si
和。di
因此,您无法做到++si
并且--di
,这需要在指令中间翻转 DF。movsb
因此不适合您的需求。
除此之外,您正在加载di
缓冲区的开头地址,因此即使movsb
会执行您想要的操作,您也会覆盖userExp
缓冲区而不是将结果写入bwUserExp
缓冲区。
您可以将字符串指令用于您的任务,如下所示:
mov si, OFFSET userExp ; source buffer
lea di, [bx + bwUserExp - 1] ; end(!) of destination buffer
mov cx, bx ; cx = size of user input
reverse_loop:
cld ; DF=0
lodsb ; al = one character, ++si
std ; DF=1
stosb ; store character, --di
dec cx
jnz reverse_loop
cld ; DF=0 for future use
如您所见,它不是最漂亮的代码,而且看起来非常复杂,字符串指令不适合您的任务,您宁愿在没有它们的情况下完成任务,如下所示:
mov si, OFFSET userExp ; source buffer
lea di, [bx + bwUserExp] ; beyond end of destination buffer
mov cx, bx ; cx = size of user input
reverse_loop:
mov al,[si]
dec di
inc si
mov [di],al
dec cx
jnz reverse_loop
; di points at bwUserExp here
关于您的代码的其他问题
...
cmp al, 97 ;Compares character to a
jge AddtoExp ;If equal or greater than
;a user jumps to AddtoExp
cmp al, 122 ;Compares character to z
jle AddtoExp ;If equal or greater than
;a user jumps to AddtoExp
jmp GetEXP ;Jumps to GetEXP if character
;is not any of the matching
;characters
这允许用户输入例如~
(126) 作为有效字符,因为 126 >= 97。此外,我总是不赞成与 ASCII 字符一起使用的有符号数学分支,因为我认为 ASCII 字符是无符号的,但从技术上讲,这并不在您的情况下不要更改任何内容,因为您只对 97..122 范围感兴趣,因此输入一些代码高于 128 的 DOS 字符(无论如何都不是常规 ASCII)被视为负值对您来说是可以的。
您可以修复+简化这样的逻辑:
...
cmp al, 'a'
jb GetEXP ; ignore characters below 'a'
cmp al, 'z'
ja GetEXP ; ignore characters above 'z'
AddtoExp:
... valid 'a'..'z' input, add to buffer ...
和
dec cx ;Decrements cx
jcxz done ;Jumps to done if
;cx is zero
jmp DisplayExp ;Jumps to DisplayExp
...虽然这可行,但您可以做更简单、更高效的事情:
dec cx ;Decrements cx
jnz DisplayExp ;Jumps to DisplayExp until cx is zero
推荐阅读
- javascript - JSON写入文件不会更新,只是替换
- apache - 使用 OR 的 htaccess 中的禁止规则不起作用
- python - 图像画布未正确更新
- php - 使用 PHP 和 MySQL 查询为一系列数据创建 JSON
- ruby-on-rails - Net::SMTPAuthenticationError: 530-5.7.0 Authentication Required Rails Mailer 在配置中使用环境变量
- javascript - cytoscape中的边缘可以有多种颜色吗
- java - 为什么我的数组在写入数据时为空?
- angular - 访问嵌套的 FormBuilder Angular6
- angular - 在多容器 docker-compose 设置中,我应该添加什么作为 api-address?
- python - 折叠/合并行与剩余列值的一些总和