如何在 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,而是打印值 10dascii 字符。我是 assembly language 的新手,所以如何打印 0 到 100 的十进制数?

您问题的正确通用解决方案是将数字转换为字符串。为了向您展示如何操作,我对您的代码进行了下一次更改:

  • 已将 NUM 的类型从 DB 更改为 DW([=14= 需要],它将包含更大的数字)。
  • 添加变量numstrNUM转换为字符串。
  • 添加了变量 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

从现在开始,您可以使用 number2stringdollars 来显示数字。

我知道,已经 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,输出将如下所示