无法输出装配中的空间

时间:2016-05-12 06:09:56

标签: assembly x86 dos x86-16

我的汇编代码存在一个小问题。一切都正常运行,但我无法让输出在彼此之间有一个空格。例如,abc应该看起来像a b c。我尝试在mov dh, space例程中使用charloop,以便自动插入空格。

但是,当我运行程序时,它不会显示出来。我很想知道我在这里做错了什么。

.data
message db "The characters of the ASCII Table between 33 and 127 are : $"
space db " $"

.code
main proc
mov ax, @data
mov ds, ax

mov ah, 09h
lea dx, message 
int 21h

mov cx, 95

mov ah, 02h
mov dl, 33 

charloop:                  
    int 21h  
    inc dl ;starting from 0 
    mov dh, space           
    dec cx

    jnz charloop  

exit:    
    mov ax, 4C00H
    int 21h

main endp
endp

2 个答案:

答案 0 :(得分:1)

我只在循环中看到一个DOS系统调用(int 21h)。我假设您正在使用打印字符系统调用,因为您正在递增dl而不是修改内存中的字符串。

您确定它甚至会查看dh吗?我忘记了标签wiki是否有指向DOS系统调用列表的链接。此外,由于您将space的第一个字节加载到dh,因此没有任何一个字节具有$终结符的

从像db 33, " $"这样的字符串开始可能更容易,并增加其中的第一个字节。然后你仍然只需要循环中的一个系统调用。否则,您需要替换打印字符和打印空间。

; set up registers as appropriate, with  OFFSET string wherever the DOS print-string system call wants it
; Note that this is different from loading the first character like your code does into `dh`

.charloop:
    int   21h
    inc   byte ptr [some_register]
    jns   .charloop           ; will fall through on 127 -> 128, sign bit set

答案 1 :(得分:1)

要以某种方式回答这个问题,您可能会理解我会提出一个与您已有的代码性质相似的解决方案。

Int 21h/ah=02h在Ralf Brown的interrupt list中记录为:

  

DOS 1+ - 标准输出的写字符

AH = 02h
DL = character to write

Return:
    AL = last character output (despite the official docs which state
    nothing is returned) (at least DOS 2.1-7.0)

要写入的字符必须始终位于 DL 中。您可以做的是在循环之前在 DH 中放置一个空格,打印当前字符,然后暂时交换(XCHG DH DL 注册,打印空间,交换 DH DL 回到原来的样子。代码可能如下所示:

mov cx, 95

mov ah, 02h
mov dl, 33 
mov dh, space

charloop:                  
    int 21h       ;Print the character
    inc dl        ;starting from 0 
    xchg dh, dl   ;Swap DH and DL temporarily
    int 21h       ;Print the separating character (space)
    xchg dh, dl   ;Swap DH and DL back to the way they were
    dec cx
    jnz charloop 

您可以简单地将space db " $"写为mov dh, space

,而不是像使用mov dh, ' '那样在字符串中放置空格和$符号

您似乎正在使用 EMU8086 / MASM / TASM ,它支持使用EQU directive定义常量。您可以在程序顶部附近定义一个分隔符字符常量(类似于 C 中的#define):

SEPARATOR equ ' '

当您需要使用它时,它看起来像:

mov dh, SEPARATOR

这样您只需更改 SEPARATOR 常量的值即可更改要打印的分隔符。

使用DOS的Writestring中断(Int 21h/AH=09h),你可以用一个中断写出字符和空格。

  

DOS 1+ - 写入标准输出字符串

AH = 09h
DS:DX -> '$'-terminated string

Return:
   AL = 24h (the '$' terminating the string, despite official docs which
   state that nothing is returned) (at least DOS 2.1-7.0 and NWDOS)

创建一个输出缓冲区,其中第一个字符将在您开始时填充,第二个字符包含您想要的分隔符(空格),第三个字符将是终止字符$。您的代码可能如下所示:

.data
message db "The characters of the ASCII Table between 33 and 127 are : $"
outputstr db 0, ' ', '$'     ; First character will be where we place char to print, 
                             ; second char is a space, $ is end of string


.code
main proc

mov ax, @data
mov ds, ax

mov ah, 09h                  ; AH=9 write string
lea dx, message             
int 21h

mov byte ptr [outputstr], 33 ; Place starting character into first
                             ;    byte of output string 
lea dx, outputstr            ; Address of outputstr in DX for call to DOS Writestring
mov cx, 95

charloop:                  
    int 21h                  ; AH=9 to write a string  
    inc byte ptr [outputstr] ; Increment the byte at beginning of the output string 
    dec cx
    jnz charloop  

exit:    
    mov ax, 4C00H
    int 21h

main endp
endp

ret

一旦你变得更熟练并编写汇编程序,你就可以不需要 CX 计数器。你可以使用his answer(跳过非SIGN)使用JNSINC中提到的技巧来简化一点。使用{{3}}时,指令将根据结果设置SIGN标志。由于您希望在达到128时结束,因此可以在符号位清零(零)时循环。值128的位7(最左边的位)是1.在处理 BYTE 时,位7也恰好是SiGN位。此技巧仅适用于您的情况,因为您希望在达到128时结束。这意味着您可以避免将 CX 用作循环计数器。

相关问题