【问题标题】:Two loops nested inside another loop in x86 assembly两个循环嵌套在 x86 程序集中的另一个循环中
【发布时间】:2012-09-01 23:31:53
【问题描述】:

我在汇编语言中遇到了循环问题。

当我们想在嵌套循环中使用计数器寄存器进行循环时, 我们首先要做的是将计数器寄存器的值移动到外部循环的堆栈中,然后当我们完成内部循环时将其取回,这样我们就可以使用一个计数器寄存器循环到嵌套循环中每个循环的迭代次数不同。

但是嵌套循环中的嵌套循环呢?

我想打印一个由字符 S 组成的金字塔。我得到的是,

SSSSSSSSSS
SSSSSSSSS
SSSSSSSS
SSSSSSS
SSSSSS
SSSSS
SSSS
SSS
SS
S

我真正想要的是,

 SSSSSSSSSS
  SSSSSSSS
   SSSSSS
    SSSS
     SS
     S

这是我的程序代码

MOV BX,10           ; HOLD 10 IN BX FOR INNER LOOP
     MOV AX,0           ; START ITERATIONS FROM 0
     MOV CX,10          ; MAX NUMBER OF ITERATIONS

    L2:

        PUSH CX         ;PUSH CX IN A STACK
        MOV CX,BX       ;STORE NEW VALUE IN CX FOR INNER LOOP ITERATION

            L1:

                MOV DX, [SI]               ; MOVE THE STRING INTO DX
                MOV AH,02H                 ; DISPLAY EVERYTHING FROM DX
                INT 21H

            LOOP L1

        MOV DX,0AH     ;PRINT LINE FEED AFTER PRINTING EACH LINE OF ASTERIKS
        MOV AH,02H
        INT 21H

        SUB BX,01     ;DECREASE THE VALUE OF BX BY 1

        POP CX        ;RESTORE ORIGINAL VALUE OF CX FOR OUTER LOOP
        ADD AX,01     ;INCREMENT VALUE OF AX BY 1

    LOOP L2


     MOV AH, 4CH                  ;RETURN CONTROL TO DOS
     INT 21H

为了达到我想要的效果,我需要在嵌套循环中添加另一个循环来打印空格字符(即 020H)。但为此,我需要另一个计数器寄存器,但我做不到。我该如何解决这个问题?

【问题讨论】:

标签: loops assembly nested-loops tasm


【解决方案1】:

您已经在做给定 ASM 中需要做的事情。您可以将 CX 的当前值推送到堆栈(保存)并稍后将其弹出以恢复它。当您需要额外的嵌套时,您需要这样做。

在 JohnB 提供的代码中,他只是简单地添加了一个循环以在打印星号之前打印出空格。不需要额外的嵌套,这意味着它非常简单。

有点像这样:

For each line
    Print an incrementing number of spaces
    Print a decrementing number of asterisks
Repeat

这正是 JohnB 向您展示的内容。

【讨论】:

  • 是的,我看到了他的帖子,但我需要更简单,我尝试了你的算法,循环内的两个循环如何相反我的意思是 1 增加而其他减少,我设法得到两个循环递减
  • 然后添加一个“if”,打印空格或 S-es。我认为完成愿望清单没有多大意义。
  • 您可以为每个字符创建两个单独的寄存器,但最终会用完寄存器。如果你看看 JohnB 在做什么,他正在做一些数学运算来获得空格的数量:(width - numAsterisks) / 2
  • 他可以使用 DX:if (space to be printed) { MOV DX, space } else { MOV DX, "s" }; write DX;
【解决方案2】:

差不多这样?

L2:

    PUSH CX         ;PUSH CX IN A STACK

    ; insert this
    MOV CX, 10      ; width of your tree = 10
    SUB CX, BX      ; subtract length of "s" string
    SHR CX, 1       ; divide CX by 2 => number of spaces at the beginning
    JCXZ endL3      ; no spaces? don't do anything

       L3:
            MOV DX, 20H ; space character
            MOV AH,02H                 ; print space
            INT 21H

        LOOP L3

    endL3:

    MOV CX,BX       ;STORE NEW VALUE IN CX FOR INNER LOOP ITERATION

        L1:

            MOV DX, [SI]               ; MOVE THE STRING INTO DX
            MOV AH,02H                 ; DISPLAY EVERYTHING FROM DX
            INT 21H

        LOOP L1

    MOV DX,0AH     ;PRINT LINE FEED AFTER PRINTING EACH LINE OF ASTERIKS
    MOV AH,02H
    INT 21H

    SUB BX,01     ;DECREASE THE VALUE OF BX BY 1

    POP CX        ;RESTORE ORIGINAL VALUE OF CX FOR OUTER LOOP
    ADD AX,01     ;INCREMENT VALUE OF AX BY 1

LOOP L2

顺便说一句,您初始化和递增 AX 的目的是什么?将数据移动到 AH/AL 时,无论如何都要覆盖它。

【讨论】:

  • 我正在增加 AX 以将循环从 0 增加到 10,我做错了吗?
  • 是的,你是,因为你的“写”操作破坏了 AX 的值。但是,这并不重要,因为无论如何您都不会使用存储在 AX 中的值。
  • 我们被告知 AX 值用于定义循环的初始值,即如果 Ax=0,则循环从 0 开始,一直到 CX 的值。不是吗? P.S:能否请您在您的代码中详细添加 cmets,我将非常感谢,因为我还是一个新手并且没有非常强大的概念
  • 不,如果 CX 不为零,LOOP 会递减 CX 并跳转,请参见此处:en.wikibooks.org/wiki/X86_Assembly/… 它与 AX 无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多