在程序集中从键盘读取缓冲区

Posted

技术标签:

【中文标题】在程序集中从键盘读取缓冲区【英文标题】:Read buffer from keyboard in Assembly 【发布时间】:2018-03-05 18:52:55 【问题描述】:

我需要从带有缓冲区的键盘读取字符串。

在示例和文献的帮助下,我设法编写了这段代码,但是当我尝试打印出我插入的字符串时,它只会给我消息“再次输入你的字符串:”。

为了打印我插入的内容,我应该在我的代码中进行哪些更改?

.model small

stack 100h

.data

    ;reading buffer
    buffSize DB 255       ;Number of maximum characters than can be read
    read DB ?             ;Number of characters that was read
    buffer  DB 255 dup (?) ;Read characters are placed here

    ;Other data
    input DB "Input your string: $",13,10
.code

Start:

    MOV ax,@data
    MOV ds,ax

    MOV ah,9
    MOV dx, OFFSET input
    INT 21h                     ;Prints input string

    MOV ah, 0Ah
    MOV dx, OFFSET buffSize
    INT 21h                     ;Text is read

    MOV bx, OFFSET buffer       ;Address of buffer is inserted to bx
    MOV cl, read                ;Content of read is inserted to cl
    MOV ch, 0                   ;In cl there is a number of inserted characters

    MOV byte ptr [ds:bx], '$'

    MOV ah, 9
    MOV dx, OFFSET buffer
    INT 21h

    MOV ah,4Ch
    INT 21h
END Start

【问题讨论】:

您是否将实际代码复制/粘贴到您的问题中,还是您手动重写了它?实际上,它甚至可能无法编译,reading buffer 行看起来像是注释,而nextLine 无法按照您的方式工作。如果您使用的是 dosbox,您很可能在某处从您的主机操作系统映射了 .asm 文件,因此只需在文本编辑器中打开它并复制/粘贴真实源代码。否则从我看到的你的代码将打印你输入的内容。不仅如此,它还应该从那个开始,一直到地址nextLine,在那里它会找到'$' 字符串终止符,ah=9 需要它。 我已经手动重写了它的 drom 示例,但不是所有的代码。整个代码将字符串的字母更改为小写。我试图阅读和打印字符串。阅读缓冲区是我的代码中的一个注释,但我在此站点中编辑文本时不小心删除了。所以我的理解是,我应该在我的代码中添加一个 $ ?我怎样才能做到这一点? (例如,显示我可以通过编写此行 MOV byte ptr [ds:bx], '$' 来做到这一点,但它没有用。我在问题中编辑了我的代码) bufSize 是 255,但您只保留 25 个字节(另一个错字?或者您不了解程序集的刚性,以及在编译期间必须如何以固定方式保留内存,或编写(相当多的)代码来处理动态内存)。当用户输入:“ABC”并按回车键时,您在内存中有 FF 03 41 42 43 0D ?? ?? ...(或者可能是 0A,不确定,检查调试器,还要重新检查我输入的长度是否正确,不确定它是 3 还是4)。您必须计算该<EOL> 的地址(取决于输入字符串的大小),然后用'$' 覆盖该字符。 但这仅适用于您想通过int 21h, ah=9 输出字符串时,它期望字符串$ 终止。您也可以按返回的长度逐个字符地输出它,而不添加任何终止符,或者您可以直接写入视频内存,根本不使用非常慢的 Bios/DOS 中断,等等......有很多方法(可能的计算定义),如何获得相同的结果(在您的情况下,B800:<somewhere> 的 VGA 内存将包含字母的 ASCII 值,例如 65 用于 A 及其颜色属性,因此 gfx 卡将绘制文本。 好吧,奇怪的是,内存是按字节寻址的,每个ASCII字符是1个字节,所以OFFSET buffer + 0是第一个输入字符的地址,+1是第二个,+2是第三个......所以基本上你想将输入的长度添加到地址buffer。 (并且输入的长度是8位,地址是16位,所以你需要将长度值零扩展为16b才能添加)...... SO充满了这些问题,很难找到它们(通过SO搜索),试试谷歌。 【参考方案1】:
input DB "Input your string: "
nextLine db "$",13,10

nextLine 不会做太多事情。将“$”放在13,10之后。 最好也分隔 输入 文本在同一行

input    db "Input your string: $"
nextLine db 13,10,"$"

buffSize DB 255       ;Number of maximum characters than can be read
read DB ?             ;Number of characters that was read
buffer  DB 25 dup (?) ;Read characters are placed here

如果您允许输入 255 个字符,您还应该定义一个足够大的缓冲区! 25 dup (?) 远小于规定的 255 大小。


要重新打印输入,在文本后面放一个 $

mov  bx, OFFSET buffer     ;Start of the text
add  bl, read              ; plus the number of characters in the text
adc  bh, 0                 ;Maybe there was a carry from previous addition!
mov  byte ptr [bx], "$"    ;DOS needs string $-terminated
mov  ah, 09h               ;DOS.DisplayString
mov  dx, OFFSET buffer
int  21h

【讨论】:

谢谢,编辑了我的代码,但主要问题是如何打印字符串.. 它实际上将“输入...”这个词变成了我写的东西。例如,当我输入“Hello”时,会打印“Hello your string: Hello” @DeividasBražėnas 这可能是因为您没有修复您的nextLine。你能确认你在调试器中看到损坏的内存内容吗? (不在屏幕上,屏幕无关紧要)......你可能不能,因为你没有调试器。但这意味着您将浪费几天的时间,因为在没有调试器的情况下进行汇编编程就像是蒙着眼睛组装机器人。 那是因为你改变了主意,放弃了使用 nextLine。有了它,程序就好了! @Tommylee2k 从来没有缓冲区溢出的危险!使用 OP 使用的(最大)设置 buffSize DB 255,DOS 最多可以返回 254 个字符 终止回车。由于此回车包含在返回的计数中,因此“$”字符写在回车之上,因此保持在缓冲区的范围内。 【参考方案2】:

您已将“$”放在缓冲区的开头。试试

    mov di, cx
    mov [bx+di], '$'

【讨论】:

我应该把它放在哪里? 代替 mov [bx], '$'。

以上是关于在程序集中从键盘读取缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

scanf()函数分析

USB 键盘 - 缓冲文件

关于环形缓冲区

windows下C语言非阻塞方式读取键盘缓冲区

C语言控制台窗口图形界面编程:键盘事件

stdin流和缓冲区