【问题标题】:Assembly Input up to 8 chars to string and output the reversing string汇编 输入最多 8 个字符到字符串并输出反转字符串
【发布时间】:2018-12-20 17:30:30
【问题描述】:

我有一个作业问题要从用户那里得到最多 8 个字符的字符串中的一个新行并反向打印

我编写了一个代码,它应该从字符串中获取每一位并将其放入堆栈中,然后将其返回到字符串中,以便将其反转并在新行中打印。但是当我运行文件时,它只是停留在输入上并且没有让我做某事

我是组装新手,我们使用的是 tasm1~1.4。

这是我的代码:

    STA SEGMENT STACK
        DB 100H DUP (0)
    STA ENDS

    DATA SEGMENT
        MSG1 DB 'ENTER STRING (Maximum is 8) : $'
        MSG2 DB 'REVERS IS : $'
        ISTR DB 10 DUP(0)
    DATA ENDS

    CODE SEGMENT
        ASSUME CS:CODE,DS:DATA,SS:STA
    MAIN:
        MOV AX, DATA
        MOV DS, AX
        LEA DX, MSG1
        MOV AH, 09H
        INT 21H
        MOV DX, 0
    ;INPUT
        MOV DX, OFFSET ISTR
        MOV AH, 0AH
        INT 21H
        MOV SI, DX
        MOV CL, [SI+1]
        ADD SI, 2
        MOV DX, 0
        MOV BL, CL
    TOSTACK:
        MOV DX, [SI]
        PUSH DX
        INC SI
        LOOP TOSTACK
        MOV DL, 10
        MOV AH, 02H
        INT 21H
        LEA DX, MSG2
        MOV AH, 09H
        INT 21H
        MOV DX, 0
        MOV CL, BL
        MOV SI, 2
    FROMSTACK:
        POP DX
        MOV AH, 02H
        INT 21H
        INC SI
        LOOP FROMSTACK

        MOV AX, 4C00H
        INT 21H

    CODE ENDS
        END MAIN

【问题讨论】:

  • 评论您的代码,尤其是如果您希望其他人提供帮助。学习使用调试器(例如非常用户友好的 turbo 调试器)来单步执行您的代码,看看哪里出了问题。
  • 慢速 loop 指令使用 CX(在 16 位模式下),而不仅仅是 CL。您正在编写 CL,但我没有看到您将零扩展到 CX。不过,IDK 为什么在推送之前将其存储在[si+1] 的内存中。如果您要手动存储,只需在读取输入时创建一个缓冲区和dec 指向其中的指针,然后在写入时向前循环。 (或将整个缓冲区传递给写入字符串函数。)

标签: assembly tasm emu8086


【解决方案1】:

但是当我运行文件时,它只是卡在输入上......

这是因为在使用 DOS 输入函数 0Ah 时,你需要事先告诉 DOS 你的输入缓冲区的大小。使用像 ISTR DB 10 DUP(0) 这样的定义,您实际上根本没有请求缓冲区!
您的程序中的正确定义是

ISTR DB 9, 0, 9 DUP(0)

第一个字节指定输入缓冲区的大小。把它放在 DesiredNumberOfCharacters + 1
第二个字节指定缓冲区已经包含多少个字符。把它放在

您可以在我的另一篇帖子How buffered input works 中找到有关此 DOS 功能的更多信息。

一旦您的输入有效,您需要修复程序的 TOSTACK 部分中的一些问题:

  • LOOP 指令依赖于整个CX 寄存器,但您只填充了CL,即CX 的低字节。只需添加mov ch, 0
    这显然意味着您还需要复制到 BX 而不是 BL 以准备 FROMSTACK 部分。
  • 因为用户可以选择根本不提供任何字符,所以您的程序需要为这种情况做好准备。一个jcxz EXIT 就足够了。
  • 输入缓冲区中的每个字符都保存在一个字节中。因此,您的代码不应读取单词

.

    mov     si, offset ISTR + 1
    mov     cl, [si]     ; Characters read 0, 1, 2, ... 8
    mov     ch, 0
    jcxz    EXIT
    mov     bx, cx       ; Save count
TOSTACK:
    inc     si
    mov     dl, [si]     ; This is a byte
    push    dx           ; Don't care about high byte in DH
    loop    TOSTACK

    ...

    mov     cx, bx       ; Restore count ( is GT 0 )
FROMSTACK:
    pop     dx           ; Still don't care about DH
    mov     ah, 02h
    int     21h
    loop    FROMSTACK
EXIT:
    mov     ax, 4C00h
    int     21h

摆脱缓慢的LOOP指令很容易:

    mov     si, offset ISTR + 1
    mov     cl, [si]     ; Characters read 0, 1, 2, ... 8
    mov     ch, 0
    jcxz    EXIT
    mov     bx, cx       ; Save count
TOSTACK:
    inc     si
    mov     dl, [si]     ; This is a byte
    push    dx           ; Don't care about high byte in DH
    dec     cx
    jnz     TOSTACK

    ...

FROMSTACK:
    pop     dx           ; Still don't care about DH
    mov     ah, 02h
    int     21h
    dec     bx
    jnz     FROMSTACK
EXIT:
    mov     ax, 4C00h
    int     21h

【讨论】:

  • 如果你去掉loop,你可以直接使用dec cl / jnz。不使用loop 的好处之一是您可以选择循环条件。
  • @PeterCordes 我保留了扩展名,因为它在dec cxdec bx 中提供了更短的编码。削减了两个字节...
  • 如果您正在优化代码大小和/或真正的 8086(其中代码获取是主要的性能瓶颈,因此在循环内节省空间是一个胜利),那么您 应该使用loop。我认为在 486 及更高版本上速度较慢,但​​在原始 8086 上实际上很好。
  • 谢谢,我会测试一下。我刚开始学习大会。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多