在 ms-dos/assembly x86-16 中将字符串中的单个字符打印到标准输出

Printing individual characters from a string to standard output in ms-dos/assembly x86-16

我是 x86-16 位编程的新手。我对如何正确调用函数 2 以从字符串中单独读取字符感到非常困惑。如果有人有任何想法,将不胜感激。下面的代码显示了我当前的尝试(其中之一)。

    .model small
    .data
        message db "Hello, DOS Here!", 0dh, 0ah
    .code
    main proc
        mov ax, @data
        mov ds, ax
    L1:
        mov ah, 2
        mov bx, 1
        int 21h
        loop L1

        .EXIT
    main endp
    end main

我还应该使用 push 和 pop 以相同的方法但向后打印字符串。我确定我遗漏了一些明显的东西。当它打印出来时,我得到的只是几行英镑符号。 (十二月:156;十六进制:9C)

警告:我已经几十年没有这样做了,而且我面前没有可以做到这一点的编译器。这看起来像是一项作业,所以我不打算编写代码,但我会为您指明正确的方向。

Int 21h function 2 要求您将 dl 设置为等于您要输出的字符。这里不需要压入和弹出,因为 DOS 不使用堆栈来传递参数。首先,在您的循环之外,您想将一个寄存器指向消息的地址,例如:MOV si, message。然后,您需要从消息中取消引用单个字节并将其放入 dl。这将需要使用间接地址表示法。然后就可以调用中断21h,写入字符了。

至于循环,有几种方法可以处理它。您可以使用计数器,其中 cx 是典型的寄存器,并使用 LOOP 语句或 DECJNZ 语句。或者您可以在字符串的末尾放置一个标记,并在您点击该标记时终止循环。为此通常使用空字符。您还需要移至字符串中的下一个字符。您可以通过添加索引或在循环的每次迭代中递增 si 寄存器的值来实现。像 INC si

综上所述,有一种更简单的方法可以避免循环,但可能是作弊。看看interrupt 21h function 9

是的,使用函数 9 是 'cheating',因为它是其他练习之一(这是一个简单的练习)。我已经修改了我的代码并让它以开头字符开头。我只需要弄清楚如何让它继续循环,以便它继续读取字符串而不是任意停止。到目前为止,这是我得到的(打印 H 和 15 个 e):

       .model small
    .data
        message db "Hello, DOS Here!"
    .code
    main proc
        mov ax, @data
        mov ds, ax

        mov ah, 2
        mov cx, 16
        mov dl, message
    L1: 
        int 21h
        mov dl, message + 1
        loop L1

        .EXIT
    main endp
    end main

使用此定义 message db "Hello, DOS Here!", 0dh, 0ah,下一段代码将打印完整消息:

mov  ah, 02h
mov  dl, message     ;Get the H character
int  21h
mov  dl, message+1   ;Get the e character
int  21h
mov  dl, message+2
int  21h
mov  dl, message+3
int  21h
mov  dl, message+4
int  21h
mov  dl, message+5
int  21h
mov  dl, message+6
int  21h
mov  dl, message+7
int  21h
mov  dl, message+8
int  21h
mov  dl, message+9
int  21h
mov  dl, message+10
int  21h
mov  dl, message+11
int  21h
mov  dl, message+12
int  21h
mov  dl, message+13
int  21h
mov  dl, message+14
int  21h
mov  dl, message+15
int  21h
mov  dl, message+16   ;Get the 0Dh carriage return
int  21h
mov  dl, message+17   ;Get the 0Ah linefeed
int  21h

相当愚蠢,你说呢?
为了使用循环并获得更紧凑的代码,我们需要:

  1. 将您的邮件地址输入地址寄存器。您可以选择 SIDIBXBP。我在下面的代码中选择了 BX
  2. 在此地址读取一个字节。
  3. 用DOS输出字节
  4. 增加地址寄存器中的指针。
  5. 对所有文本重复步骤 2、3、4、5,检查它是否是您刚刚输出的 换行符。因为在您的文本中这是最后一个字符。

这个循环的一个版本:

 mov  bx, OFFSET message  ;1.
Again:
 mov  dl, [bx]            ;2.
 mov  ah, 02h             ;3.
 int  21h
 inc  bx                  ;4.
 cmp  dl, 0Ah             ;5.
 jne  Again

I'm also supposed to use push and pop to be able to print the string in the same method but backwards.

要完成您的下一个任务,您可以在第 2 步和第 3 步之间放置一个 push dx。然后再编写一个循环来显示反转的字符串:

Again2:
 pop  dx
 mov  ah, 02h
 int  21h
 cmp  dl, "H"
 jne  Again2

这里的陷阱是

  • 你不应该在其他(真实)字符之前输出换行符和回车符 return ==> 提示:在开始第二个循环之前执行 2 pops
  • 你不能轻易假设 "H" 只会作为文本的第一个字符出现 ==> 提示:计算 pushs
  • 的数量