程序集在打印消息时跳过第一个符号
Assembly skips first symbol while printing a message
这是我第一次用 Assembly 编写代码,所以代码可能并不完美(甚至不是很好),但这是我的工作方式,不要评判太多:)。它是为使用 DOSbox 和 Turbo Assembler/Linker/Debugger 的 Intel x86 编写的,如果有任何区别的话。任务是从用户那里获取一行并将所有大写字母转换为小写字母(保留其他所有内容)。问题是,当我一个一个地打印每个符号并在其后添加'\n'(新行)时,它工作正常,但是,我需要我的输出在一行中,所以当我尝试打印时没有' \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 进行比较。我建议您阅读 DOS.BufferedInput 函数在 中的工作原理。 DOS 总是包含回车符 return 作为终止字节。
您已选择与零进行比较,因为您是从全零输入缓冲区开始的。然而,当 DOS return 控制您的代码时,您正在寻找的零可能甚至不再存在!如果用户在键盘上首先键入一个(非常)长的文本,然后开始退格,零就消失了。
如果零仍然在正确的位置,还有第二个原因导致失败。您在打印 之后放置了零支票 ,这没有意义,因为它不是输入的一部分,是吗?现在 ASCII 代码 0 打印为 space 字符,因为零之前的字节不可避免地是一个回车 return (13),光标已经移动到行的开头和第一个字符行被删除。打印 ASCII 码 0 真的没什么神奇的。
你可以这样写。因为您确实要打印终止符 return,所以即使 'empty input' 也包含一个字节。因此 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
这是我第一次用 Assembly 编写代码,所以代码可能并不完美(甚至不是很好),但这是我的工作方式,不要评判太多:)。它是为使用 DOSbox 和 Turbo Assembler/Linker/Debugger 的 Intel x86 编写的,如果有任何区别的话。任务是从用户那里获取一行并将所有大写字母转换为小写字母(保留其他所有内容)。问题是,当我一个一个地打印每个符号并在其后添加'\n'(新行)时,它工作正常,但是,我需要我的输出在一行中,所以当我尝试打印时没有' \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 进行比较。我建议您阅读 DOS.BufferedInput 函数在
您已选择与零进行比较,因为您是从全零输入缓冲区开始的。然而,当 DOS return 控制您的代码时,您正在寻找的零可能甚至不再存在!如果用户在键盘上首先键入一个(非常)长的文本,然后开始退格,零就消失了。
如果零仍然在正确的位置,还有第二个原因导致失败。您在打印 之后放置了零支票 ,这没有意义,因为它不是输入的一部分,是吗?现在 ASCII 代码 0 打印为 space 字符,因为零之前的字节不可避免地是一个回车 return (13),光标已经移动到行的开头和第一个字符行被删除。打印 ASCII 码 0 真的没什么神奇的。
你可以这样写。因为您确实要打印终止符 return,所以即使 'empty input' 也包含一个字节。因此 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