在 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
语句或 DEC
和 JNZ
语句。或者您可以在字符串的末尾放置一个标记,并在您点击该标记时终止循环。为此通常使用空字符。您还需要移至字符串中的下一个字符。您可以通过添加索引或在循环的每次迭代中递增 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
相当愚蠢,你说呢?
为了使用循环并获得更紧凑的代码,我们需要:
- 将您的邮件地址输入地址寄存器。您可以选择
SI
、DI
、BX
和 BP
。我在下面的代码中选择了 BX
。
- 在此地址读取一个字节。
- 用DOS输出字节
- 增加地址寄存器中的指针。
- 对所有文本重复步骤 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
pop
s
- 你不能轻易假设 "H" 只会作为文本的第一个字符出现 ==> 提示:计算
push
s 的数量
我是 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
语句或 DEC
和 JNZ
语句。或者您可以在字符串的末尾放置一个标记,并在您点击该标记时终止循环。为此通常使用空字符。您还需要移至字符串中的下一个字符。您可以通过添加索引或在循环的每次迭代中递增 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
相当愚蠢,你说呢?
为了使用循环并获得更紧凑的代码,我们需要:
- 将您的邮件地址输入地址寄存器。您可以选择
SI
、DI
、BX
和BP
。我在下面的代码中选择了BX
。 - 在此地址读取一个字节。
- 用DOS输出字节
- 增加地址寄存器中的指针。
- 对所有文本重复步骤 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
pop
s - 你不能轻易假设 "H" 只会作为文本的第一个字符出现 ==> 提示:计算
push
s 的数量