【问题标题】:Tasm - Assembly LoopTasm - 组装循环
【发布时间】:2017-08-27 17:50:55
【问题描述】:

我想在用户输入正确密码后显示“Hello World”,但如果密码不正确,程序将提示输入 Yes(Y)/No(N),如果用户输入 Yes(Y),则程序将给用户 3 次机会显示“Hello World”,如果用户输入 No(N),程序将退出。 我的问题是,每次我选择Yes(Y)时,程序一直循环,如果我输入No(N),它就会结束,

这是我的代码(我已经跳过了一些部分)

   ...
    org 0100h
    .code

    mov ah, @data
    mov ds, ah


    mov cx, 3

    pool:
    dec cx
    jz full    ;jump if equal to zero seems of no effect, the loop is still counting

    dsply:
    <codes here are for requesting and comparing the password>

    ...
    ...
    ...
    cmp bl, al
    jne errr
    cmp cl, al
    jmp welc

    errr:
    mov ah, 9
    lea dx, pmpt   ; Displays whether the Yes(Y)/No(N)
    int 21h
    mov ah, 1
    mov cl, al
    int 21h

    cmp cl, 'Y'
    je dsply
    cmp cl, 'N'
    je endmain

    loop pool

    full:
    mov ah, 9
    lea dx, att   ;att will display You've Exceeded
    int 21h
    jmp endmain

    welc:
    mov ah, 9
    lea dx, hw  ; Displaying Hello World
    int 21h
    jmp endmain

    endmain:
    mov ah, 4ch
    int 21h
    end main

我不知道这些代码是否正确,我现在没有我的代码副本,而且,如果我的代码和问题的解释看起来很愚蠢,我很抱歉,但如果有人可以请帮忙,如果你能给我你的另一个想法,那就太好了,而且更棒:)

【问题讨论】:

  • 您不应该发布甚至可能不是实际代码的代码。但是想想你在代码中对 CX 寄存器做了什么,这应该会告诉你为什么它永远不会为零。也不应该有理由使用loop,然后手动使用dec cx
  • 您是否尝试过使用调试器单步执行此操作?
  • @SamiKuhmonen 我的错误,对不起,????,但仍然,谢谢!非常感谢您的建议
  • @PeterCordes 我没有,我不知道怎么做,

标签: loops assembly x86 tasm dosbox


【解决方案1】:
errr:
  mov ah, 9
  lea dx, pmpt   ; Displays whether the Yes(Y)/No(N)
  int 21h
  mov ah, 1
  mov cl, al
  int 21h

您根本没有将您的输入放在CL 寄存器中!
您需要将mov cl, al 指令移动到下方 int 21h 指令。


mov ah, @data
mov ds, ah

我不明白这是如何工作的。您应该在这里使用 16 位寄存器。

mov ax, @data
mov ds, ax

cmp cl, al
jmp welc

这个无条件 jmp 很可能会变成有条件 jne


pool:
dec cx
jz full

循环顶部不需要 dec cxjz full。下面的loop pool 指令已经完成了所需的操作。 (由Sami Kuhmonen 观察)。

但是...
因为the loop instruction is slow(由Peter Cordes观察)你应该避免使用它并用类似于你在循环顶部的冗余指令的代码替换它。
但是等等,还有一件事不对劲!您的循环使用CX 寄存器作为其迭代计数器,但同时循环主体内的代码将相同的CX 寄存器用于其他目的。这不可避免地会导致问题!您需要注意如何使用这些寄存器。

这是一个解决方案:

    mov     cx, 3
pool:
    push    cx      ;(1) Save the iteration counter on the stack
dsply:
    ...
    <codes here are for requesting and comparing the password>
    ...
    pop     cx      ;(1) Restore the iteration counter
    dec     cx
    jnz     pool
full:
    mov     ah, 9

cmp cl, 'Y'
je dsply
cmp cl, 'N'
je endmain

一旦你的程序运行起来,你就会在这里遇到一个潜在的问题。当用户输入小“y”或小“n”时会发生什么?
程序不会识别它!

最好将输入大写:

and cl, 11011111b
cmp cl, 'Y'
je  dsply
cmp cl, 'N'
je  endmain

请按预期使用 DOS API。 TerminateWithReturnCode 函数确实需要AL 寄存器中的返回码。这是一个真正的小努力:

mov  ax, 4C00h  ;Function number in AH, Return code in AL
int  21h

【讨论】:

  • 请不要建议人们开始使用loopIt's slow on modern CPUs,学习使用条件分支制作循环的更通用方法可能会更好。我已经看到太多的 16 位代码只是盲目地使用 loop,而使用其他东西作为循环条件而不绑定 cx 会更方便。显然,初学者陷入了认为loop 是循环的唯一方法的陷阱。
  • 嗨,Sep,感谢您在我的代码中提出的建议,真的很感谢您告诉我它有什么问题,xD,尽管我没有编辑,我会与您保持联系并测试了你的修改,你看起来太棒了!,非常感谢!,:)
  • @PeterCordes 感谢您对loop 指令的建议。我用学分编辑了我的答案。下次我应该说对不起,因为我已经习惯了使用这个指令......
  • @user8141558 请阅读我修改后的答案。也许这里的新信息也将回答您提出的后续问题!
  • 酷,谢谢。我没有意识到 OP 正在使用loop。我在代码中看到dec cx / jz,然后意识到这是一团糟,所以我失去了兴趣,跳到答案看看你要说什么,因为你已经完成了弄清楚问题所在的工作。我以为你已经介绍了 loop 而不是 jmp 回到 dec/jz 或其他东西。告诉人们在每个 16 位答案中替换 loop 关于不相关的问题会很无聊,所以只有当人们在 OP 还没有使用 loop 时才会真正困扰我。 (但在这种情况下,问题是关于循环的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 2015-02-01
相关资源
最近更新 更多