gpt4 book ai didi

assembly - 缓冲输入如何工作

转载 作者:行者123 更新时间:2023-12-02 18:59:45 25 4
gpt4 key购买 nike

下一个程序中的输入工作正常,但是当我要求显示输出时,DOS
根本不显示任何内容!这怎么可能?

        ORG     256
mov dx, msg1
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 0Ah ;DOS.BufferedInput
int 21h
mov dx, msg2
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 09h ;DOS.WriteString
int 21h
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
msg1: db 'Input : ', '$'
buf: db 20 dup ('$')
msg2: db 13, 10, 'Output : ', '$'
; --------------------------------------

最佳答案

查看您如何定义输入缓冲区(buf: db 20 dup ('$')),我明白了
您想偷工减料,并已将输入终止为$
重新显示它。可悲的是,这弄乱了DOS输入所需的设置
功能0Ah,并且您的程序存在潜在的缓冲区严重问题
超限。
此外,使用$终止并不是您可以做的最明智的选择
因为$字符可能已经出现在输入字符中。
我在下面介绍的所有示例程序都将使用零终止
代替。

使用int 21h AH=0Ah输入文本

Buffered STDIN Input函数从键盘获取字符,并且
继续这样做,直到用户按下Enter键。所有
字符和最后的回车符放置在
从调用程序提供的输入缓冲区的第3个字节开始
通过DS:DX中的指针。
字符计数(不包括最后的回车符)存储在
输入缓冲区的第二个字节。
调用程序有责任告诉DOS
存储空间是。因此,您必须将其长度放在
调用此函数之前输入缓冲区。允许输入1
字符,您将存储大小设置为2。允许输入254
您将存储大小设置为255个字符。
如果您不希望从模板中调出任何先前的输入,
那么最好也将第二个字节清零。基本上,模板是
输入缓冲区中预先存在(且有效)的内容是调用程序的
提供。如果预先存在的内容无效,则模板不是
可用。

令人惊讶的是,此功能的编辑功能有限。


转义从当前输入中删除所有字符。
当前输入被放弃,但停留在屏幕上,光标置于
下一行,输入第一次开始的位置。
Backspace从当前输入中删除最后一个字符。
如果输入停留在屏幕上的单个行中,则按预期方式工作。
另一方面,如果输入跨越几行,则此后退间距将
停在屏幕的左边缘。从那时起,
逻辑输入和视觉输入之间存在差异,因为在逻辑上
退格将继续进行,直到到达存储空间的第一个位置!
F6在当前输入中插入文件结尾字符(1Ah)。
屏幕将显示“ ^ Z”。
F7在当前输入中插入一个零字节。
屏幕将显示“ ^ @”。
ctrlEnter转换到下一行(执行
回车和换行),则不会在当前输入中添加任何内容,
不能回去。


还有更多的编辑键可用。它们都让人联想到EDLIN.EXE,
古老的DOS行编辑器,这是一个文本编辑器,前一行
成为您在其上构建下一行的模板。


F1将一个字符从模板复制到新行。
F2 + ...将所有字符从模板复制到新行,直到指定的字符为止。
F3将模板中所有剩余的字符复制到新行。
F4 + ...跳过模板中的字符,向上
到指定的字符。
F5使新行成为新模板。
转义清除当前输入,并使模板保持不变。
删除跳过模板中的一个字符。
插入进入或退出插入模式。
退格键删除新行的最后一个字符,并将光标移回模板中的一个字符。
左与Backspace相同。
右与F1相同。


通过此功能扩展选项卡。标签扩展是替换的过程
ASCII 9除以一系列一个或多个空格(ASCII 32),直到光标到达
列位置是8的倍数。
此选项卡扩展仅在屏幕上发生。存储空间将保存ASCII 9。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。
当前行。

示例1,缓冲的STDIN输入。

        ORG     256                     ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov ah, 0Ah ;DOS.BufferedInput
int 21h
mov si, msg2
call WriteStringDOS
mov si, buf+2
movzx bx, [si-1] ;Get character count
mov word [si+bx+1], 10 ;Keep CR, append LF and 0
call WriteStringDOS
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 255, 16, "I'm the template", 13, 255-16-1+2 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 10, 'You chose ', 0
; --------------------------------------


使用 int 21h AH=3Fh输入文本

与预定义的句柄0(在 BX中)一起使用时,此 Read From File Or Device
函数从键盘获取字符并继续这样做,直到
用户按Enter。所有字符(不超过127个)和
最后的回车符和附加的换行符放在一个私人
DOS内核中的缓冲区。现在,它将成为新模板。
此后,函数将写入 DS:DX提供的缓冲区中
CX参数中请求的字节数。如果 CX指定了一个数字
小于此输入生成的字节数,一个或多个
需要其他对该函数的调用才能检索完整的输入。
只要还有剩余字符需要提取,此功能将
不要使用键盘启动另一个输入会话!两者之间甚至如此
不同的程序或同一程序的会话。

上一节中介绍的所有编辑键均可用。

选项卡仅在屏幕上展开,而不在模板中展开。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。


如果终止换行符不在返回的字节中,则返回当前行。
如果终止换行符位于返回的字节中,则返回下一行。


示例2a,“从文件或设备读取”,一次读取所有文件。

        ORG     256                     ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov cx, 127+2 ;Max input is 127 chars + CR + LF
xor bx, bx ;STDIN=0
mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
mov bx, ax ;Bytes count is less than CX
mov si, msg2
call WriteStringDOS
mov si, buf
mov [si+bx], bh ;Keep CR and LF, append 0 (BH=0)
call WriteStringDOS
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 127+2+1 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 'You chose ', 0
; --------------------------------------


示例2b,“从文件或设备读取”,一次拾取一个字节。

        ORG     256                     ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov cx, 1
xor bx, bx ;STDIN=0
mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
mov si, msg2
call WriteStringDOS
mov si, dx ;DX=buf, CX=1, BX=0
Next: mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
call WriteStringDOS ;Display a single byte
cmp byte [si], 10
jne Next
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
msg1: db 'Choose color ? ', 0
msg2: db 10, 'You chose '
buf: db 0, 0
; --------------------------------------


使用 int 2Fh AX=4810h输入文本

DOSKEY Buffered STDIN Input函数只能被 if the DOSKEY.COM TSR was installed调用。它的运行方式与常规Buffered类似
STDIN输入功能0Ah(参见上文),但具有相同的编辑功能
作为DOS命令行的可能性,包括使用所有
DOSKEY特殊键。


Up从历史记录中获取上一个项目。
向下获取历史记录中的下一项。
F7显示历史记录中所有项目的列表。
AltF7清除历史记录。
... F8查找以...开头的项目
F9从历史记录中按编号选择一个项目。
AltF10删除所有宏定义。


在DOS 6.2上,存储空间始终限制为128个字节,从而允许输入
127个字符,并有强制退回的余地。不是
可以预加载模板,因此请始终设置输入的第二个字节
缓冲为零。
在DOS Win95上,如果您安装了
使用诸如 doskey /line:255之类的命令来运行DOSKEY.COM TSR。有可能
使用模板预加载存储空间。这带来了Win95版本
非常接近输入功能0Ah可行的方法。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。
当前行。如果字符计数为零,则表示用户输入了
尚未扩展的DOSKEY宏的名称。你不
看到未展开的线!需要第二次调用该功能
返回此时间后,光标将位于的最后一个字符之后
展开的文字。
特殊之处在于,当扩展多命令宏( $T)时,您只能
获取第一个命令的扩展文本。的其他调用
需要功能以获得其他扩展文本。尽管所有这些都是
在用户内部从COMMAND.COM之类的命令外壳中非常有用
应用程序,这真让人讨厌,您不知道什么时候发生。

由于输入的文本已添加到命令历史记录中,因此不可避免
历史记录中填充了无关的项目。当然不是您想看到的
在DOS提示符下!

示例3,调用DOSKEY.COM。

        ORG     256                     ;Create .COM program
cld
mov ax, 4800h ;DOSKEY.CheckInstalled
int 2Fh ; -> AL
test al, al
mov si, err1
jz Exit_
Again: mov si, msg1
call WriteStringDOS
mov dx, buf
mov ax, 4810h ;DOSKEY.BufferedInput
int 2Fh ; -> AX
test ax, ax
mov si, err2
jnz Exit_
cmp [buf+1], al ;AL=0
je Again ;Macro expansion needed
mov si, msg2
call WriteStringDOS
mov si, buf+2
movzx bx, [si-1] ;Get character count (is GT 0)
mov word [si+bx+1], 10 ;Keep CR, append LF and 0
Exit_: call WriteStringDOS
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 128, 0, 128+2 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 13, 10, 'You chose ', 0
err1: db 'N/A', 13, 10, 0
err2: db 'Failed', 13, 10, 0
; --------------------------------------


使用 int 21h AH=08h输入文本


由于堆栈溢出施加的30000字节限制,文本在下面的答案中继续...


理解来源有问题吗?我使用的汇编程序:


将以点(。)开头的标签视为第一级本地标签
将以冒号(:)开头的标签视为第二级本地标签
是单指令多操作数(SIMO),因此 push cx si
转换为 push cx push si

关于assembly - 缓冲输入如何工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47379024/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com