這是我第一次用匯撰寫作,所以代碼可能并不完美(甚至不好),但這是我的作業方式,不要過多評判 :) . 它是用DOSbox和Turbo Assembler/Linker/Debugger為Intel x86撰寫的,如果這有什么區別的話。任務是從用戶那里得到一行,并將所有的大寫字母轉換成小寫字母(其他都保持原樣)。問題是,當我一個一個地列印每個符號,并在其后面加上''(新行)時,就會發現 '(新行)時,效果很好,但是,我需要我的輸出是在一行中,所以當我嘗試列印時不加'' 的時候,它就會跳過第一個符號。為什么它會這樣做,如何解決這個問題,以及為什么用''可以作業? '?
; 任務是獲得用戶的輸入并將任何大寫字母轉換成小寫字母
;并列印修改后的行
.model small
.stack 100h
.data
start_msg db "輸入一行:", 0Dh, 0Ah, 24h ; "行
", $
out_msg db "轉換后的行:", 0Dh, 0Ah, 24h
緩沖區 DB 100, ?, 100 dup(0)
.代碼
開始。
mov dx, @data ; 移動資料到dx中
mov ds, dx ; 將dx(資料)移入資料段。
列印start_msg
mov ah, 09h
mov dx, offset start_msg
int 21h
讀取輸入的行并將其放入緩沖區
mov ah, 0Ah
mov dx, offset buffer
int 21h
; 列印'
'
mov dl, 0Ah
mov ah, 02h
int 21h
; 列印out_msg
mov ah, 09h
mov dx, offset out_msg
int 21h
將輸入行的第一個字符的指標放在bx中
mov bx, offset buffer 2
loopString:
mov dl,[bx] ; 從緩沖區中讀出一個模擬字符并放入dl中。
cmp dl, 'A' ; 如果符號比'A'"多",跳到ifUpper
jae ifUpper
; 列印simbol
列印。
mov ah, 02h
int 21h
檢查,如果行結束
inc bx ; bx
cmp dl, 0
je endLoop ; 結束回圈
; 代碼的臨時部分,在每個列印出來的符號后面放上'
'放在每個列印的符號后面
如果它被評論,則跳過輸入行的第一個字符
如果使用的話,一切都能正常作業,但是我需要最終的輸出是在一行中。
;mov dl, 0Ah ; 取消對我的注釋
;mov ah, 02h ; 取消對我的注釋
;int 21h ; 取消對我的注釋
jmp loopString ; 如果沒有檢測到行結束,則再次回圈。
ifUpper:
cmp dl, 'Z' ; 檢查符號是否比'Z'"多"。
ja print ; 它不是上行,只是列印出符號
add dl, 20h ; 32 (將大寫轉換為小寫)
jmp print ; 列印轉換后的符號
endLoop:
mov ah, 4ch ; 回傳到dos
mov al, 0 ; 錯誤
int 21h
結束開始
取消注釋 "Uncomment me "的行,以查看帶有和不帶有''的輸出。 '. 預先感謝。
uj5u.com熱心網友回復:
cmp dl, 0 je endLoop ; 結束回圈
這是你代碼中存在問題的部分。你應該與13的值進行比較。我建議你在這個Q/A>中閱讀DOS.BufferedInput函式的作業原理。DOS總是將回車鍵作為一個結束位元組。
你選擇了與零進行比較,因為你是從一個全部為零的輸入緩沖區開始的。然而,當DOS將控制權回傳給你的代碼時,你正在尋找的零可能已經不在那里了!這時,你就會發現,你的代碼已經不在了。如果用戶在鍵盤上首先鍵入一個(非常)長的文本,然后開始后退,那么零就不存在了。
萬一零點仍然在正確的位置,還有第二個原因會導致失敗。你把對零的檢查放在了列印后,這沒有意義,因為它不是輸入的一部分,不是嗎?現在,ASCII碼0被列印成一個空格字符,由于0前面的位元組不可避免地是一個回車符(13),游標已經移到了行的開頭,行中的第一個字符被擦除。列印ASCII代碼0真的沒有什么神奇的地方。
這就是你可以寫的方式。因為你確實想列印結束時的回車,即使是 "空輸入 "也是由一個位元組組成的。因此,一個Repeat-Until回圈就可以了。
標籤:
mov bx, offset buffer 2
重復。
mov dl, [bx].
cmp dl, 'A
jb print
cmp dl, 'Z
ja 列印
add dl, 32 ; 制作LCase
print:
mov ah, 02h
int 21h
inc bx
cmp dl, 13
jne Repeat ; 直到13被列印出來
mov dl, 10
int 21h
