下一个程序中的输入工作正常,但是当我要求显示输出时,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/