汇编程序 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】:

问题在于您使用的寄存器:AXCX 用于中断和循环,因此您可以使用其他寄存器,例如,SI 而不是 CXDI 而不是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 循环中打印的主要内容,如果未能解决你的问题,请参考以下文章

当值不存在时,默认 sum 运算符为 0

汇编语言16位环境搭建(Windows 7 32位)

16位汇编 多文件 intel汇编 编译器masm5.0 调用子程序库即静态库的自定义函数 WINDOWS

ruby - 当值更改时将数组拆分为子数组并忽略/删除该值

当值重复3次或更多次时创建新列

当值为 NULL 时,Apache Pig 不尊重 ELSE 语句