汇编程序 MASM,当值为 0 或以下时在 JNZ 循环中打印
Posted
技术标签:
【中文标题】汇编程序 MASM,当值为 0 或以下时在 JNZ 循环中打印【英文标题】:Assembler MASM, printing in JNZ loop when value is 0 or below 【发布时间】:2016-12-02 19:23:25 【问题描述】:我的任务是编写一个程序,该程序将在下面创建作为输出:
ABCD******
ABCD***
ABCD
我的代码是:
kod segment
org 100h
assume cs:kod
start:
mov cx,3
mov bx,3
mov ax,6
mov ah, 02h
PETLA_ZEW:
push cx
mov cx,4
mov dl, 'A'
PETLA_CIAG:
int 21h
inc dl
dec cx
jnz PETLA_CIAG
push ax
mov cx, ax
mov dl, '*'
PETLA_GWIAZD:
int 21h
dec cx
jnz PETLA_GWIAZD
sub ax, 3
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
push bx
mov cx, bx
mov dl, ' '
PETLA_SPACJE:
int 21h
dec bx
jnz PETLA_SPACJE
pop bx
add bx, 3
pop cx
dec cx
jnz PETLA_ZEW
koniec:
mov ah, 4ch
int 21h
kod ends
end start
但问题是,当我第二次减去 ax 时,在称为 PETLA_GWIAZD 的循环中,它的值为 0,这导致了无限循环。减法时我应该使用其他循环吗?也许在循环之前进行一些验证检查?我刚开始使用 Assembly,还不太了解...
谢谢!
【问题讨论】:
当ax
为零时,您想要输出零星。因此,您对“循环之前的验证检查”的想法对我来说听起来不错。并且有相当简单的方法可以做到这一点。在mov cx,ax
之后您可以添加jcxz SKIP_GWIAZD
,并在sub ax,3
之后添加新标签SKIP_GWIAZD:
在print <new line>
代码部分之前。以下是不同条件跳转的描述:***.com/documentation/x86/5808/control-flow/20470/…
哦,实际上jcxz
并没有在那里描述,哇。对不起。 Here 是一些文档,包括 jcxz
。
是的,我刚开始阅读有关其他跳跃的更多信息,尝试了几种变体+您的想法,但它似乎仍然不起作用。我在 mov cx, ax 和实际的 SKIP_GWIAZD: 之后添加了 jcxz SKIP_GWIAZD,就在 koniec: 程序结束之前,但它仍然不起作用。我这样做是因为最后一行中的最后一件事只是字母,所以我们不想在那之后有任何东西(下一行也不是空格)。
抱歉,格式化出现问题...是的,我刚开始阅读更多关于其他跳跃的内容,尝试了几种变体 + 你的想法,但它似乎仍然不起作用。我在mov cx, ax
和实际的SKIP_GWIAZD:
之后添加了jcxz SKIP_GWIAZD
,就在程序结束之前,即koniec:
,但它仍然不起作用。我这样做是因为最后一行中的最后一件事只是字母,所以我们不想在那之后有任何东西(下一行也不是空格)。 – sakcaj 7 分钟前
但是您不能直接跳到结尾,因为堆栈中还有一些值等等。我会想要打印 new_line。可能让您头疼的是空格的打印,因为它们属于下一行。我建议您首先移动空格,然后“输出”0
空格(与0
跳过 gwiazdy 的方式相同),因此循环内的代码将具有人类逻辑:<0-6 spaces><ABCD><6-0 stars><newline>
。
【参考方案1】:
问题在于您使用的寄存器:AX
和 CX
用于中断和循环,因此您可以使用其他寄存器,例如,SI
而不是 CX
和 DI
而不是AX
:
kod segment
org 100h
assume cs:kod
start:
mov si,3 ;◄■■ INSTEAD OF CX.
mov bx,3
mov di,6 ;◄■■ INSTEAD OF AX.
mov ah, 02h
PETLA_ZEW:
mov cx,4
mov dl, 'A'
PETLA_CIAG:
int 21h
inc dl
dec cx
jnz PETLA_CIAG
cmp di, 0 ;◄■■ IF COUNTER == 0 ...
je koniec ;◄■■ ... NO MORE ASTERISKS.
mov cx, di ;◄■■
mov dl, '*'
PETLA_GWIAZD:
int 21h
dec cx
jnz PETLA_GWIAZD
sub di, 3 ;◄■■
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
push bx
mov cx, bx
mov dl, '_'
PETLA_SPACJE:
int 21h
dec bx
jnz PETLA_SPACJE
pop bx
add bx, 3
dec si ;◄■■
jnz PETLA_ZEW
koniec:
mov ah, 4ch
int 21h
kod ends
end start
【讨论】:
@sakcaj,出于测试目的,我将空格 ' ' 替换为下划线 '_' :) 谢谢!看起来你是对的。但是我怎么知道我可以使用哪些寄存器呢?默认情况下它们是否都是“空的”,它只取决于我编写的程序?例如,我可以只使用 EDX、DX、DH、DL 和 CX 来计算吗?互联网上有很多关于它的... @sakcaj,一些寄存器用于中断,另一些用于一些指令(如循环),学习何时以及如何使用哪些寄存器需要时间,但是,如果你不使用某些注册,你可以给它一些用途,比如计数器。 @sakcaj 你可以使用任何你想要的寄存器,但是其中一些对于某些指令有特殊用途(例如保持sp
作为堆栈指针工作),并且在 16b 模式下,一些允许用于内存寻址,有些不是,等等。这不像你不能使用ax
作为计数器。它调用int 21h
会破坏它,并且您必须通过阅读所有内容的文档、您调用的内容或使用其中一个 ABI 来进行验证,它确实指定了哪些可能会改变,哪些不会。 dl/dh
也是 dx
的一部分,这是 edx
的一部分,它不像 4 个单独的寄存器,而是同一个寄存器的 8/16/32 位部分。
谢谢你们,我会记住在下次使用之前检查我想使用的寄存器的用途:)。以上是关于汇编程序 MASM,当值为 0 或以下时在 JNZ 循环中打印的主要内容,如果未能解决你的问题,请参考以下文章