如何在 emu 8086 中用汇编语言打印 0 到 100?
How can I print 0 to 100 in assembly language in emu 8086?
在这里,我尝试了在 emu8086
中打印 10 到 0 十进制数。
.MODEL SMALL
.STACK 100H
.DATA
NUM DB 58D
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX
START:
CMP NUM,48D
JGE PRINT
JMP END_
PRINT:
MOV AH,2
MOV DL,NUM
INT 21H
DEC NUM
JMP START
END_:
MOV AH,4CH
MAIN ENDP
END MAIN
它在打印 9 到 0 时工作得很好,但它没有打印 10,而是打印值 10d
的 ascii
字符。我是 assembly language
的新手,所以如何打印 0 到 100 的十进制数?
您问题的正确通用解决方案是将数字转换为字符串。为了向您展示如何操作,我对您的代码进行了下一次更改:
- 已将
NUM
的类型从 DB
更改为 DW
([=14= 需要],它将包含更大的数字)。
- 添加变量
numstr
,NUM
转换为字符串。
- 添加了变量
lbk
(每个数字后只是一个换行符)。
- 添加了 proc
number2string
,将 AX 中的数字转换为 SI 指向的字符串(这是最重要的)。
- 添加了 proc
dollars
,用美元符号填充 numstr
(需要显示,并在转换下一个数字之前清除字符串)。
这是您的代码,显示从 0 到 100 的数字(注释将帮助您理解它):
.MODEL SMALL
.STACK 100H
.DATA
NUM DW ?
lbk db 13,10,'$' ;LINE BREAK.
numstr db '$$$$$' ;STRING FOR 4 DIGITS.
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX
MOV NUM, 0 ;FIRST NUMBER.
START:
CMP NUM, 100 ;IF NUM <= 100...
JBE PRINT ;...DISPLAY NUM.
JMP END_
PRINT:
; MOV AH,2 ;THIS CODE
; MOV DL,NUM ;DISPLAYS
; INT 21H ;ONE CHAR ONLY.
;CONVERT NUMBER TO STRING.
mov si, offset numstr
mov ax, num
call number2string ;RETURNS NUMSTR.
;DISPLAY STRING.
mov ah, 9
mov dx, offset numstr
int 21h
;DISPLAY LINE BREAK.
mov ah, 9
mov dx, offset lbk
int 21h
INC NUM ;NUM++.
JMP START
END_:
MOV Ax,4C00H
int 21h
MAIN ENDP
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : AX = NUMBER TO CONVERT.
; SI = POINTING WHERE TO STORE STRING.
number2string proc
call dollars ;FILL STRING WITH $.
mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov dx, 0 ;NECESSARY TO DIVIDE BY BX.
div bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp ax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : SI = POINTING TO STRING TO FILL.
proc dollars
mov cx, 5
mov di, offset numstr
dollars_loop:
mov bl, '$'
mov [ di ], bl
inc di
loop dollars_loop
ret
endp
;------------------------------------------
END MAIN
从现在开始,您可以使用 number2string
和 dollars
来显示数字。
我知道,已经 5 年了。但这可能对其他人有帮助。
; Here at first, @ indicating start of label and $ indicating start of procedure. if multiple label and procedure is present in assembly code.
; Then distinguishing label & procedure can be done easily. It's just my own way of coding. You can ignore this style
;Algorthm for Decimal Input
; number = 0
; while input != "\n" do
; number = number * 10
; input a charchter
; number = number + input
; count++
;Algorthm for Decimal Output
; for i = 1 to count do
; reminder = number % 10
; push reminder
;
; for i = 1 to count do
; pop reminder
; print reminder
.model small ; declaring this code will be consists of one data segment and one code segment
.stack 100h ; stack is initializeed to offset address at 100h
.data ; this is data segment
n_line db 0ah,0dh,"$" ;here declared a string named n_line which is define byte(8 bit), which value is null('$')
;and 0ah is for line feed (moves to next output line) & 0dh is for carriage return
n dw ? ; n is defne word(16 bit) variable which value is not initialized yet
i db ? ; i is define byte(8 bit) variable which value is not initialized yet
count db ? ; i is define byte(8 bit) variable which value is not initialized yet
reminder db ? ;reminder is define byte(8 bit) variable which value is not initialized yet
flag db 0 ;flag is define byte(8 bit) variable which value is initialized as 0
num dw ? ; num is defne word(16 bit) variable which value is not initialized yet
.code
$set_number proc
@while:
mov ah,1 ; taking input here
int 21h
mov cl,al
sub cl,30h
cmp al,13 ;checking if input is new line or not
je @break_while
mov ax,n ; al = n
mul bl ; al = n * 10
mov n,ax ; n = n * 10
mov ch,0 ;as n variable is dw so...
add n,cx ; n = n + al = (n * 10) + al
inc count ; count = count + 1
jmp @while
@break_while:
ret ; here instruction pointer will jump to the next line of calling this procedure
$set_number endp ; end of procedure
$get_number proc
@for_loop_1_init:
mov i,1d
@for_loop_1:
mov dl,count ; before executing loop,every time i'm storing count variable to al register
cmp i,dl ; it means here, cmp i,count
jg @for_loop_1_end
mov ah,0 ; here chances may be ah store some value,so clearing ah register
cmp flag,0 ; think like boolean value
jne @try ; suppose, n = 135d .So each time,i'm ensuring quotient is divded & excluding reminder from ah register
mov ax,n
mov flag,1
div bl ; al = ax/bl and ah = reminder
jmp @final
@try:
mov ah,0
div bl
@final:
xor cx,cx ; clearing cx register
mov cl,ah
push cx ;push reminder
inc i
jmp @for_loop_1
@for_loop_1_end:
; uncomment these, if you want to print in row wise
; lea dx,n_line
; mov ah,9
; int 21h
@for_loop_2_init:
mov i,1d
@for_loop_2:
mov al,count ;before executing loop,every time i'm storing count variable to al register
cmp i,al ;it means here, cmp i,count
jg @for_loop_2_end
pop dx ;stack's top value is stored in dx now
add dx,30h ; 30h is equivalent to 48d, means ascii charchter 0
mov ah,2
int 21h
inc i
jmp @for_loop_2
@for_loop_2_end:
ret ; here instruction pointer will jump to the next line of calling this procedure
$get_number endp ; end of procedure
main proc
mov ax,@data
mov ds,ax
mov bl,10d ; bl = 10d
@input:
xor cx,cx ; clearing cx register
call $set_number
@print:
cmp n,0
je @stop
xor ax,ax ; clearing ax register
xor cx,cx ; clearing cx register
xor dx,dx ; clearing dx register
call $get_number
mov dl,32d ; 32d is for space in ascii
mov ah,2
int 21h
;These register can be affected so for futher looping,clearing all
xor ax,ax ; clearing ax register
xor cx,cx ; clearing cx register
xor dx,dx ; clearing dx register
mov count,0
mov flag,0
dec n ; This Question was to print number in decreasing order
mov ax,n
@repeat: ;in this label,i am counting length of n
mov ah,0
div bl
inc count
cmp al,0
jnle @repeat
jmp @print
@stop:
mov ah,4ch ; terminate the programme
int 21h
main endp ; ending of main procedure
end main ; ending of code segment
如果输入 = 105,输出将如下所示
在这里,我尝试了在 emu8086
中打印 10 到 0 十进制数。
.MODEL SMALL
.STACK 100H
.DATA
NUM DB 58D
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX
START:
CMP NUM,48D
JGE PRINT
JMP END_
PRINT:
MOV AH,2
MOV DL,NUM
INT 21H
DEC NUM
JMP START
END_:
MOV AH,4CH
MAIN ENDP
END MAIN
它在打印 9 到 0 时工作得很好,但它没有打印 10,而是打印值 10d
的 ascii
字符。我是 assembly language
的新手,所以如何打印 0 到 100 的十进制数?
您问题的正确通用解决方案是将数字转换为字符串。为了向您展示如何操作,我对您的代码进行了下一次更改:
- 已将
NUM
的类型从DB
更改为DW
([=14= 需要],它将包含更大的数字)。 - 添加变量
numstr
,NUM
转换为字符串。 - 添加了变量
lbk
(每个数字后只是一个换行符)。 - 添加了 proc
number2string
,将 AX 中的数字转换为 SI 指向的字符串(这是最重要的)。 - 添加了 proc
dollars
,用美元符号填充numstr
(需要显示,并在转换下一个数字之前清除字符串)。
这是您的代码,显示从 0 到 100 的数字(注释将帮助您理解它):
.MODEL SMALL
.STACK 100H
.DATA
NUM DW ?
lbk db 13,10,'$' ;LINE BREAK.
numstr db '$$$$$' ;STRING FOR 4 DIGITS.
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX
MOV NUM, 0 ;FIRST NUMBER.
START:
CMP NUM, 100 ;IF NUM <= 100...
JBE PRINT ;...DISPLAY NUM.
JMP END_
PRINT:
; MOV AH,2 ;THIS CODE
; MOV DL,NUM ;DISPLAYS
; INT 21H ;ONE CHAR ONLY.
;CONVERT NUMBER TO STRING.
mov si, offset numstr
mov ax, num
call number2string ;RETURNS NUMSTR.
;DISPLAY STRING.
mov ah, 9
mov dx, offset numstr
int 21h
;DISPLAY LINE BREAK.
mov ah, 9
mov dx, offset lbk
int 21h
INC NUM ;NUM++.
JMP START
END_:
MOV Ax,4C00H
int 21h
MAIN ENDP
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : AX = NUMBER TO CONVERT.
; SI = POINTING WHERE TO STORE STRING.
number2string proc
call dollars ;FILL STRING WITH $.
mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov dx, 0 ;NECESSARY TO DIVIDE BY BX.
div bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp ax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : SI = POINTING TO STRING TO FILL.
proc dollars
mov cx, 5
mov di, offset numstr
dollars_loop:
mov bl, '$'
mov [ di ], bl
inc di
loop dollars_loop
ret
endp
;------------------------------------------
END MAIN
从现在开始,您可以使用 number2string
和 dollars
来显示数字。
我知道,已经 5 年了。但这可能对其他人有帮助。
; Here at first, @ indicating start of label and $ indicating start of procedure. if multiple label and procedure is present in assembly code.
; Then distinguishing label & procedure can be done easily. It's just my own way of coding. You can ignore this style
;Algorthm for Decimal Input
; number = 0
; while input != "\n" do
; number = number * 10
; input a charchter
; number = number + input
; count++
;Algorthm for Decimal Output
; for i = 1 to count do
; reminder = number % 10
; push reminder
;
; for i = 1 to count do
; pop reminder
; print reminder
.model small ; declaring this code will be consists of one data segment and one code segment
.stack 100h ; stack is initializeed to offset address at 100h
.data ; this is data segment
n_line db 0ah,0dh,"$" ;here declared a string named n_line which is define byte(8 bit), which value is null('$')
;and 0ah is for line feed (moves to next output line) & 0dh is for carriage return
n dw ? ; n is defne word(16 bit) variable which value is not initialized yet
i db ? ; i is define byte(8 bit) variable which value is not initialized yet
count db ? ; i is define byte(8 bit) variable which value is not initialized yet
reminder db ? ;reminder is define byte(8 bit) variable which value is not initialized yet
flag db 0 ;flag is define byte(8 bit) variable which value is initialized as 0
num dw ? ; num is defne word(16 bit) variable which value is not initialized yet
.code
$set_number proc
@while:
mov ah,1 ; taking input here
int 21h
mov cl,al
sub cl,30h
cmp al,13 ;checking if input is new line or not
je @break_while
mov ax,n ; al = n
mul bl ; al = n * 10
mov n,ax ; n = n * 10
mov ch,0 ;as n variable is dw so...
add n,cx ; n = n + al = (n * 10) + al
inc count ; count = count + 1
jmp @while
@break_while:
ret ; here instruction pointer will jump to the next line of calling this procedure
$set_number endp ; end of procedure
$get_number proc
@for_loop_1_init:
mov i,1d
@for_loop_1:
mov dl,count ; before executing loop,every time i'm storing count variable to al register
cmp i,dl ; it means here, cmp i,count
jg @for_loop_1_end
mov ah,0 ; here chances may be ah store some value,so clearing ah register
cmp flag,0 ; think like boolean value
jne @try ; suppose, n = 135d .So each time,i'm ensuring quotient is divded & excluding reminder from ah register
mov ax,n
mov flag,1
div bl ; al = ax/bl and ah = reminder
jmp @final
@try:
mov ah,0
div bl
@final:
xor cx,cx ; clearing cx register
mov cl,ah
push cx ;push reminder
inc i
jmp @for_loop_1
@for_loop_1_end:
; uncomment these, if you want to print in row wise
; lea dx,n_line
; mov ah,9
; int 21h
@for_loop_2_init:
mov i,1d
@for_loop_2:
mov al,count ;before executing loop,every time i'm storing count variable to al register
cmp i,al ;it means here, cmp i,count
jg @for_loop_2_end
pop dx ;stack's top value is stored in dx now
add dx,30h ; 30h is equivalent to 48d, means ascii charchter 0
mov ah,2
int 21h
inc i
jmp @for_loop_2
@for_loop_2_end:
ret ; here instruction pointer will jump to the next line of calling this procedure
$get_number endp ; end of procedure
main proc
mov ax,@data
mov ds,ax
mov bl,10d ; bl = 10d
@input:
xor cx,cx ; clearing cx register
call $set_number
@print:
cmp n,0
je @stop
xor ax,ax ; clearing ax register
xor cx,cx ; clearing cx register
xor dx,dx ; clearing dx register
call $get_number
mov dl,32d ; 32d is for space in ascii
mov ah,2
int 21h
;These register can be affected so for futher looping,clearing all
xor ax,ax ; clearing ax register
xor cx,cx ; clearing cx register
xor dx,dx ; clearing dx register
mov count,0
mov flag,0
dec n ; This Question was to print number in decreasing order
mov ax,n
@repeat: ;in this label,i am counting length of n
mov ah,0
div bl
inc count
cmp al,0
jnle @repeat
jmp @print
@stop:
mov ah,4ch ; terminate the programme
int 21h
main endp ; ending of main procedure
end main ; ending of code segment
如果输入 = 105,输出将如下所示