assembly - 装配体在打印消息时跳过第一个符号
问题描述
这是我第一次用Assembly写代码,所以代码可能并不完美(甚至不是很好),但这是我的工作方式,不要过多判断:)。它是使用 DOSbox 和 Turbo Assembler/Linker/Debugger 为 Intel x86 编写的,如果这有什么不同的话。任务是从用户那里获取一行并将所有大写字母转换为小写字母(保持其他所有内容不变)。问题是,当我一个接一个地打印每个符号并在其后添加 '\n'(new line) 时,它工作正常,但是,我需要我的输出在一行中,所以当我尝试在没有 ' 的情况下打印时\n',它会跳过第一个符号。为什么会这样,如何解决它,以及为什么它与 '\n' 一起使用?
; Task is to get input from the user and convert any upper case letters into lower case
; and print modified line
.model small
.stack 100h
.data
start_msg db "Enter a line:", 0Dh, 0Ah, 24h ; "line\n", $
out_msg db "Converted line:", 0Dh, 0Ah, 24h
buffer db 100, ?, 100 dup(0)
.code
start:
mov dx, @data ; moves data into dx
mov ds, dx ; moves dx (data) into data segment
; prints start_msg
mov ah, 09h
mov dx, offset start_msg
int 21h
; reads inputed line and puts it into buffer
mov ah, 0Ah
mov dx, offset buffer
int 21h
; prints '\n'
mov dl, 0Ah
mov ah, 02h
int 21h
; prints out_msg
mov ah, 09h
mov dx, offset out_msg
int 21h
; puts pointer to the first character of inputed line in bx
mov bx, offset buffer + 2
loopString:
mov dl,[bx] ; reads a simbol from buffer and puts into dl
cmp dl, 'A' ; if symbol is "more" than 'A', jump to ifUpper
jae ifUpper
; prints simbol
print:
mov ah, 02h
int 21h
; checks, if line ended
inc bx ; bx++
cmp dl, 0
je endLoop ; ends looping
; temp part of code, puts '\n' after each printed symbol
; if it is commented, skips first character from inputed line
; everything works if used, however I need final output to be in one line.
;mov dl, 0Ah ; Uncomment me
;mov ah, 02h ; Uncomment me
;int 21h ; Uncomment me
jmp loopString ; if line end was not detected, loops again
ifUpper:
cmp dl, 'Z' ; checks if symbol is "more" than 'Z'
ja print ; it is not upper, just prints the symbol
add dl, 20h ; +32 (converts upper to lower)
jmp print ; prints converted symbol
endLoop:
mov ah, 4ch ; back to dos
mov al, 0 ; error
int 21h
end start
Un\comment 说“取消注释我”的行以查看带有和不带有 '\n' 的输出。提前致谢。
解决方案
cmp dl, 0 je endLoop ; ends looping
这是您的代码有问题的部分。您应该改为与值13进行比较。我建议您在此 Q/A中了解 DOS.BufferedInput 函数的工作原理。DOS 总是将回车作为终止字节。
您选择与零进行比较是因为您从全零输入缓冲区开始。但是,当 DOS 将控制权交还给您的代码时,您正在寻找的零可能已经不存在了!如果用户在键盘上首先输入一个(非常)长的文本,然后开始退格,那么零就消失了。
如果零仍然在正确的位置,那么它失败的第二个原因。您在打印后放置了零检查,这没有意义,因为它不是输入的一部分,是吗?现在 ASCII 代码 0 打印为空格字符,并且因为零之前的字节不可避免地是回车符 (13),所以光标已经移动到行首,并且行上的第一个字符被删除。打印 ASCII 码 0 真的没有什么神奇之处。
这就是你可以写它的方式。因为您确实想打印终止的回车,所以即使是“空输入”也包含一个字节。因此,Repeat-Until 循环很好。
mov bx, offset buffer + 2
Repeat:
mov dl, [bx]
cmp dl, 'A'
jb print
cmp dl, 'Z'
ja print
add dl, 32 ; Make LCase
print:
mov ah, 02h
int 21h
inc bx
cmp dl, 13
jne Repeat ; Until 13 was printed
mov dl, 10
int 21h
推荐阅读
- python - 如何用 pandas 计算百分比和累积百分比
- azure-devops - Azure DevOps Server 2019 Build 已排队但未启动
- ios - SwiftUI - 单击 NavigationLink 时触发其他操作
- java - 是否有可能将多个设备 LatLng 与 1 个设备 LatLng 进行比较?
- flutter - 如何从列表中获取特定的 DocumentSnapshot
- github - GitHub 删除的文件正在抛弃语言统计信息
- c# - 从 JSON 中删除附加文本
- react-native - 在 createStackNavigator() 之前执行代码
- java - 检查 Firebase 实时数据库中是否存在字段
- amazon-web-services - 调用 UpdateService 操作时的 AWS ECS InvalidParameterExcpetion