Assembly 如何从DOS中的标准输入中读取字符,以便重定向工作?

Assembly 如何从DOS中的标准输入中读取字符,以便重定向工作?,assembly,stdin,dos,x86-16,io-redirection,Assembly,Stdin,Dos,X86 16,Io Redirection,我目前正在写一个DOS程序。在这个程序中,我使用服务从标准输入读取字符。然而,当我重定向文件中的标准输入时,EOF检测似乎并没有按预期工作。我用nasm语法编写了这个示例程序来说明这个问题: org 0x100 ; read characters and sum them up main: xor bx,bx .1: mov ah,1 int 0x21 xor ah,ah add bx,ax cmp al,0x1a ; eof

我目前正在写一个DOS程序。在这个程序中,我使用服务从标准输入读取字符。然而,当我重定向文件中的标准输入时,EOF检测似乎并没有按预期工作。我用nasm语法编写了这个示例程序来说明这个问题:

    org 0x100

    ; read characters and sum them up
main:   xor bx,bx

.1: mov ah,1
    int 0x21
    xor ah,ah
    add bx,ax
    cmp al,0x1a       ; eof reached?
    jnz .1

    mov cx,4
.2: mov si,bx
    shr si,12
    mov dl,[hextab+si] ; convert to hex
    mov ah,2
    int 0x21
    shl bx,4
    loop .2

    ret

hextab: db '0123456789ABCDEF'
当我重定向文件中的标准输入时,程序将挂起,除非该文件某处包含^Z。我的印象是EOF标记为service 21/AH=01,在DOS中返回^Z,然而,情况似乎并非如此

如何从DOS中的标准输入中读取字符,使其与重定向标准输入一起工作,以便在输入未重定向的情况下将字符回显到屏幕上,并检测到EOF情况?理想情况下,我希望具有类似于
getchar()函数的功能。

您应该使用MS-DOS“read”函数。通常,您希望避免使用过时的MS-DOS1.x API函数。输出函数(AH=1,AH=9)通常是可以的,但其余大部分函数不应使用,除非您需要在MS-DOS 1下运行程序。MS-DOS2.0引入了一组全新的类Unix文件函数,这些函数的大部分工作原理与等效的Unix函数相同。因此,在本例中,MS-DOS读取函数与Unix
read
系统调用一样,接受三个参数:文件句柄、缓冲区地址和要读取的字符数。与Unix一样,文件句柄0表示标准输入,1表示标准输出,2表示标准错误

因此,您可以重写您的示例,使用MS-DOS读(AH=3Fh)和写(AH=40h)函数,如下所示:

    ORG 0x100

main:
    xor di, di
    mov bp, buf
    mov dx, bp
    mov cx, 1

loopchar:
    mov ah, 0x3f
    int 21h
    jc  error
    dec ax
    js  eof           ; EOF reached?
    cmp BYTE [bp], 0x1a
    je  eof
    add di, [bp]
    jmp loopchar

eof:
    inc cx
    mov ax, di
    mov al, ah
    call printhex1
    jc  error
    xchg ax, di

printhex1:
    mov bx, hextab
    aam 16
    xlat
    mov [bp + 1], al
    mov al, ah
    xlat    
    mov [bp], al
    mov bx, 1
    mov ah, 0x40
    int 21h

error:
    ret

buf db  0, 0

hextab: db '0123456789ABCDEF'

如果你运行真正的MS-DOS,会发生同样的事情吗?@MichaelPetch我还没试过!明天让我检查一下。@MichaelPetch在真正的MS-DOS上(我测试了MS-DOS 6.02),基本上发生了相同的事情,除了^Z在输入被重定向时甚至没有终止程序。另一个区别是,当输入被重定向时,它被复制到终端。@fuz十六进制打印代码真的太聪明了,不利于自身。它只会比你的代码快,因为它一次打印两位数。如果您想要较短的代码,那么最好不要使用查找表,因为该表比它所替换的代码大。关于较短的代码(请参见
xchg ax,di
,您是这样编写的!):只需交换
di
BP
即可减少3个字节,因为
[BP]
需要强制的零字节偏移量。更妙的是,将这些字符存储在一起还可以减少另外3个字节:
xlat
xchg-al,ah
xlat
mov[bp],ax
。然而,对于重定向意识的问题,这是一个极好的答案(+)。