尽管键入相同的代码 3 次,但我如何仅使用一次新行代码打印新行 3 次



尽管键入相同的代码 3 次,我如何仅使用一次新行代码打印新行 3 次

include emu8086.inc
ORG    100h
    PRINT 'ENTER THREE INITIALS: '
    MOV AH,1
    INT 21H
    MOV BL,AL
    INT 21H
    MOV CL,AL
    INT 21H
    MOV BH,AL
   MOV AH,2
    MOV DL,10
    INT 21H     ;NEW LINE
    MOV DL,13
    INT 21H   
    MOV AH,2
    MOV DL,BL
    INT 21h
    MOV AH,2
    MOV DL,10
    INT 21H     ;NEW LINE
    MOV DL,13
    INT 21H

    MOV DL,CL
    INT 21h 
    MOV AH,2
    MOV DL,10
    INT 21H     ;NEW LINE
    MOV DL,13
    INT 21H
    MOV DL,BH
    INT 21h
   RET               
END  

您所要做的就是将您编写了 3 次的换行代码块放入您可以call的子例程中。

PrintCRLF:
    push    ax
    push    dx
    mov     dl, 13    ;Carriage return
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    mov     dl, 10    ;Linefeed
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    pop     dx
    pop     ax
    ret

现在,程序中显示结果的部分变为:

    call    PrintCRLF
    mov     dl, bl    ;1st initial
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    call    PrintCRLF
    mov     dl, cl    ;2nd initial
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    call    PrintCRLF
    mov     dl, bh    ;3rd initial
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h

不要觉得有必要尽可能多地删除mov ah, 02h。将这些保留下来可以形成一个有据可查的程序,多年来,我已经看到BIOS/DOS实现确实破坏了AX寄存器,即使API另有说明也是如此。


作为一个例子,为了表明你可以在不调用子例程的情况下编写它,下面是一个使用循环的版本,如本注释所示:

    push    ax        ;3rd initial in AL
    push    cx        ;2nd initial in CL
    push    bx        ;1st initial in BL
    mov     cx, 3
Next:
    mov     dl, 13    ;Carriage return
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    mov     dl, 10    ;Linefeed
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    pop     dx        ;Pops 1st, 2nd, and 3rd initial to DL
    mov     ah, 02h   ;DOS.DisplayCharacter
    int     21h
    dec     cx
    jnz     Again

首先创建一个可以从主代码调用的子例程/函数,例如在主代码放置以下内容之后:

PRINT_NEW_LINE:
    MOV AH,2
    MOV DL,10
    INT 21H     ;NEW LINE  (that's really amazing comment... not)
    MOV DL,13   ; and now I realized you do 10,13 output
    INT 21H     ; but correct DOS <EOL> is 13,10
    RET         ; time to fix all that in next version below...

现在我将使用一些丑陋的技巧来创建 2x 和 3x 变体,而不仅仅是简单地调用上面的子例程,而是让 CPU 通过其代码,在调试器中尝试它是如何工作的(以及堆栈中的返回地址做什么(,然后整个新的子例程代码将是:

PRINT_NEW_LINE_THRICE:
    CALL PRINT_NEW_LINE ; do 1x EOL, and then fall into "twice" code
PRINT_NEW_LINE_TWICE:
    CALL PRINT_NEW_LINE ; do 1x EOL, and then fall into it again
PRINT_NEW_LINE:
    PUSH AX
    PUSH DX     ; store original ax, dx values
    MOV AH,2
    MOV DL,13
    INT 21H     ; output NL (new line)
    MOV DL,10
    INT 21H     ; output CR (carriage return)
    POP DX      ; restore original ax, dx value
    POP AX
    RET

现在在你的主代码中,只需做:

    CALL PRINT_NEW_LINE_THRICE

以获得 3 倍新行输出。


"三次"子例程的不那么令人困惑和棘手的变体当然是:

PRINT_NEW_LINE_THRICE:
    CALL PRINT_NEW_LINE
    CALL PRINT_NEW_LINE
    CALL PRINT_NEW_LINE
    RET

最新更新