前言:初學(xué)匯編,可能一時難以習(xí)慣這種任何事情都要“親力親為”的方式。就拿輸入輸出來說,高級語言一個函數(shù)就可以搞定的事情,在匯編中卻不是那么容易的。下面簡單介紹下8086匯編輸入輸出數(shù)字和字符串的問題。
1、輸入輸出字符串
調(diào)用21號中斷的0ah和09h號功能,可以實(shí)現(xiàn)字符串的輸入輸出
輸入字符串,調(diào)用0ah號功能
需要注意的是,中斷功能的調(diào)用大多是有一些約定的,基本上都是通過固定的寄存器傳值
拿21h中斷的0ah中斷來說,這個功能是實(shí)現(xiàn)輸入字符串的,在此之前首先要提供一個變量存放輸入的字符串,這個變量的定義方式是有要求的,如下:
buffer db 50, ?, 50 dup('$')
//db表示定義字節(jié)大小,第一個50表示想要定義一個50字節(jié)大小的變量(申請空間),?表示一個未定義的值,它會記錄輸入字符串的實(shí)際長度,
//后面表示連續(xù)定義50個字節(jié),用來存放輸入的字符串的。至于為什么要定義為'$',這是因?yàn)?$'是字符串約定的結(jié)尾符號,輸出的時候檢測到這個符號就代表一個字符串結(jié)束。
//上面完成了定義一個變量(申請空間),用來存放輸入的字符,下面還需要把這個變量的偏移地址給dx寄存器,才可以調(diào)用0ah號功能,段地址默認(rèn)為ds就不需要改了
lea dx, buffer ;送偏移地址
mov ah,0ah ;將0ah放入ah
int 21h ;輸入字符串功能調(diào)用
//下面介紹輸出字符串功能,相對輸入來說輸出字符串要簡單些
/*同樣要有一個變量,將變量的地址放入ds:dx,然后調(diào)用09h號功能8*/
outputstr db 'hello world',0dh,0ah,'$'
//0dh,0ah分別是回車換行的ascii碼,加到字符串后面表示換到下一行行首,'$'為結(jié)束標(biāo)志
lea dx outputstr ;送偏移地址
mov ah, 09h ;將09h放入ah
int 21h ;輸出字符串功能調(diào)用
一個示例
下面咱們在dosbox下實(shí)驗(yàn)下,代碼如下
功能是將輸入的字符串在下一行輸出
stack segment stack
stack ends
data segment
buffer db 50, ?, 50 dup('$')
next_row db 0dh,0ah,'$'
data ends
code segment
assume cs:code, ds:data, ss:stack
start: mov ax, data
mov ds, ax
lea dx, buffer ;輸入字符串
mov ah, 0ah
int 21h
lea dx, next_row ;換行
mov ah, 09h
int 21h
mov dx, offset [buffer+2] ;輸出字符串,注意起始地址
mov ah, 09h
int 21h
mov ah, 4ch
int 21h
code ends
end start
編譯、連接、然后執(zhí)行
2、輸入輸出字符(數(shù)字)
其實(shí)輸入輸出數(shù)字都是通過輸入輸出字符實(shí)現(xiàn)的,準(zhǔn)確的說,我們在屏幕上輸入輸出的只是某個數(shù)字(0-9)的ASCII碼值(對應(yīng)30H-39H),而8086的21H號中斷提供了輸入輸出字符的功能。21h號中斷要配合ah使用,將功能號放在ah中,再通過int 21h調(diào)用
2.1 輸入輸出字符
1號功能,輸入字符
//1號功能,輸入字符,輸入字符的ascii碼放在al中
mov ah, 1
int 21h
//2號功能,輸出字符,要輸出的字符放在dl中
mov dl 31h //31h,即1的ASCII碼
mov ah 2
int 21h
2.2 輸入輸出數(shù)字
其實(shí)輸入輸出數(shù)字本質(zhì)上也就是輸入輸出字符(串),我們輸入或輸出的只是ASCII碼值,要得到實(shí)際的數(shù)值,還要經(jīng)過轉(zhuǎn)換。除此之外,數(shù)據(jù)的大?。ㄎ粩?shù))也是受限制的,16位數(shù)二進(jìn)制寄存器能保存的無符號數(shù)范圍為0~65535,有符號數(shù)為-32768 ~ 32767,如果是用八位寄存器,可保存的數(shù)范圍就更小了。
這里都以有符號的16位為前提討論
一個比較完善的輸入十進(jìn)制數(shù)的處理流程如下:
① 調(diào)用21號中斷的1號功能輸入一個字符
② 判斷輸入字符的正負(fù),負(fù)數(shù),設(shè)置標(biāo)記,正數(shù)繼續(xù)下面步驟
③ 判斷輸入是否合法(是否為0 - 9),或結(jié)束;若非法,提示重新輸入,若結(jié)束,保存結(jié)果,否則繼續(xù)下一步
④ 將ASCII碼值轉(zhuǎn)為數(shù)值
⑤ 將已經(jīng)得到的內(nèi)容乘以10,加上本次輸入的數(shù)值
⑥ 轉(zhuǎn)①
流程圖如下:
看起來有點(diǎn)復(fù)雜,事實(shí)上還好,我們直接上代碼
;約定子程序的標(biāo)號前加proc_前綴
;輸入子程序,約定輸入范圍(-32768~32767),結(jié)果送到ax
input proc near
push bp
mov bp, sp
push bx
push cx
push dx
proc_pre_start:
xor ax, ax ;置零,以免對后面的數(shù)據(jù)產(chǎn)生影響
xor bx, bx
xor cx, cx
xor dx, dx
proc_judge_sign: ;判斷符號
mov ah, 1 ;21h-1號功能輸入一個字符存入al
int 21h
cmp al, '-'
jne proc_next ;不是負(fù)數(shù),跳到下一步,是負(fù)數(shù),設(shè)置dx為ffff
mov dx, 0ffffh
jmp proc_digit_in
proc_next:
cmp al, 30h ;判斷輸入是否合法或結(jié)束(鍵入回車al為odh)
jb proc_unexpected
cmp al, 39h
ja proc_unexpected
sub al, 30h ;得到真實(shí)數(shù)值
shl bx, 1 ;原來數(shù)據(jù)乘以10,加上al
mov cx, bx
shl bx, 1
shl bx, 1
add bx, cx
add bl, al
adc bh, 0
proc_digit_in:
mov ah, 1 ;循環(huán)輸入,直至結(jié)束
int 21h
jmp proc_next
proc_save:
cmp dx, 0ffffh ;是負(fù)數(shù),求補(bǔ),否則直接保存
jne proc_result_save
neg bx
proc_result_save:
mov ax, bx ;最終結(jié)果放入ax
jmp proc_input_done
proc_unexpected:
cmp al, 0dh
je proc_save ;如輸入回車,轉(zhuǎn)到保存結(jié)果,否則提示錯誤信息,重新輸入
dispmsg next_row
dispmsg error
jmp proc_pre_start
proc_input_done:
pop dx
pop cx
pop bx
pop bp
ret
input endp
相比起輸入數(shù)字,輸出數(shù)字就好簡單些了
一個較為完善的輸出數(shù)字的處理流程如下:
① 判斷符號,正數(shù)繼續(xù),負(fù)數(shù)求補(bǔ)并輸出一個負(fù)號
② 符號擴(kuò)展為32數(shù),免得除法溢出
③ 采用除10取余法,依次得到個位、十位上的數(shù)字,存入堆棧,并判斷商是否為0,若為零,輸出堆棧中的數(shù)據(jù),結(jié)束,否則繼續(xù)除法
流程比較簡單,就不上流程圖了,咱們直接上代碼
;輸出子程序,輸入?yún)?shù)通過堆棧傳遞,大小為一個字
output proc near
push bp
mov bp, sp
push ax
push bx
push cx
push dx
xor cx, cx
mov bx, [bp+4] ;將入?yún)⒎诺絙x
test bx, 8000h ;判斷結(jié)果是負(fù)數(shù)還是正數(shù),若為負(fù)數(shù),求補(bǔ)碼,并輸出一個負(fù)號
jz proc_nonneg
neg bx
mov dl,'-'
mov ah, 2
int 21h
proc_nonneg:
mov ax, bx
cwd ;符號擴(kuò)展為dx.ax,以免除法溢出
mov bx, 10
proc_div_again:
xor dx, dx
div bx ;除以10取余數(shù),dx:ax / bx = ax......dx
add dl, 30h
push dX ;結(jié)果存入堆棧 ,cx記錄除法次數(shù)(數(shù)據(jù)長度)
inc cx
cmp ax, 0 ;商為0,結(jié)束,否則循環(huán)
jne proc_div_again
proc_digit_out:
pop dx ;輸出
mov ah, 2
int 21h
loop proc_digit_out
proc_output_done:
pop dx
pop cx
pop bx
pop ax
pop bp
ret 2 ;退出子程序,彈出堆棧中主程序給的參數(shù)
output endp
一個示例
下面是一個示例,功能需求是輸入三個有符號16位數(shù)字x,y,z;要求求最小值并輸出
;csdn@Tao_shimmer
stack segment stack
stack ends
data segment
x dw ?
y dw ?
z dw ?
min dw ?
inputx db 'please enter the value of x: ','$'
inputy db 'please enter the value of y: ','$'
inputz db 'please enter the value of z: ','$'
outputmin db 'the minimum value of x y z is: ','$'
error db 'input error, please re-enter: ','$'
next_row db 0dh,0ah,'$'
data ends
code segment
assume cs:code, ds:data, ss:stack
;求三個數(shù)中最小值的宏,范圍(-32768~32767)
;輸入x,y,z,min結(jié)果保存到min中
min3 macro x,y,z,min
push ax
mov ax, x
cmp ax, y ;比較x和y,將較小值放入ax
jl xyzmin
mov ax, y
xyzmin:
cmp ax, z ;比較z和min(x,y)將較小值放入ax
jl save_result
mov ax, z
save_result:
mov min, ax
pop ax
endm
dispmsg macro message ;顯示字符串的宏,入?yún)槠鹗嫉刂? lea dx, message
mov ah, 9
int 21h
endm
;主程序
start: mov ax, data
mov ds, ax
dispmsg inputx ;輸入提示
call input
mov x, ax ;保存輸入
dispmsg inputy
call input
mov y, ax
dispmsg inputz
call input
mov z, ax
min3 x,y,z,min
dispmsg outputmin ;輸出提示
push min
call output
mov ah, 4ch
int 21h
;約定子程序的標(biāo)號前加proc_前綴
;輸入子程序,約定輸入范圍(-32768~32767),結(jié)果送到ax
input proc near
push bp
mov bp, sp
push bx
push cx
push dx
proc_pre_start:
xor ax, ax ;置零,以免對后面的數(shù)據(jù)產(chǎn)生影響
xor bx, bx
xor cx, cx
xor dx, dx
proc_judge_sign:
mov ah, 1 ;21h-1號功能輸入一個字符存入al
int 21h
cmp al, '-'
jne proc_next ;不是負(fù)數(shù),跳到下一步,是負(fù)數(shù),設(shè)置dx為ffff
mov dx, 0ffffh
jmp proc_digit_in
proc_next:
cmp al, 30h ;判斷輸入是否合法或結(jié)束(鍵入回車al為odh)
jb proc_unexpected
cmp al, 39h
ja proc_unexpected
sub al, 30h
shl bx, 1 ;原來數(shù)據(jù)乘以10,加上al
mov cx, bx
shl bx, 1
shl bx, 1
add bx, cx
add bl, al
adc bh, 0
proc_digit_in:
mov ah, 1 ;循環(huán)輸入,直至結(jié)束
int 21h
jmp proc_next
proc_save:
cmp dx, 0ffffh ;是負(fù)數(shù),求補(bǔ),否則直接保存
jne proc_result_save
neg bx
proc_result_save:
mov ax, bx ;最終結(jié)果dx.ax
jmp proc_input_done
proc_unexpected:
cmp al, 0dh
je proc_save ;如輸入回車,轉(zhuǎn)到保存結(jié)果,否則提示錯誤信息,重新輸入
dispmsg next_row
dispmsg error
jmp proc_pre_start
proc_input_done:
pop dx
pop cx
pop bx
pop bp
ret
input endp
;輸出子程序,輸入?yún)?shù)通過堆棧傳遞,為一個字
output proc near
push bp
mov bp, sp
push ax
push bx
push cx
push dx
xor cx, cx
mov bx, [bp+4] ;將入?yún)⒎诺絙x
test bx, 8000h ;判斷結(jié)果是負(fù)數(shù)還是正數(shù),若為負(fù)數(shù),輸出一個負(fù)號
jz proc_nonneg
neg bx
mov dl,'-'
mov ah, 2
int 21h
proc_nonneg:
mov ax, bx
cwd ;符號擴(kuò)展為dx.ax,以免除法溢出
mov bx, 10
proc_div_again:
xor dx, dx
div bx ;除以10取余數(shù),dx:ax / bx = ax......dx
add dl, 30h
push dX ;結(jié)果存入堆棧 ,cx記錄除法次數(shù)(數(shù)據(jù)長度)
inc cx
cmp ax, 0 ;商為0,結(jié)束,否則循環(huán)
jne proc_div_again
proc_digit_out:
pop dx ;輸出
mov ah, 2
int 21h
loop proc_digit_out
proc_output_done:
pop dx
pop cx
pop bx
pop ax
pop bp
ret 2 ;退出子程序,彈出堆棧中主程序給的參數(shù)
output endp
code ends
end start
下面是在dosbox下的測試截圖文章來源:http://www.zghlxwxcb.cn/news/detail-424910.html
參考資料
《匯編語言程序設(shè)計(jì)》第五版 錢曉捷等文章來源地址http://www.zghlxwxcb.cn/news/detail-424910.html
到了這里,關(guān)于8086匯編:輸入輸出數(shù)字、字符、字符串功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!