我不理解如何使用中断21,AH=0ah。

12

我的信息来自这里。该任务要求编写一个程序,最多读取20个字符,将这些字符转换为大写,并以大写形式打印输入。

我不知道如何从int21 / AH = 0ah访问输入。除非我理解了上面的链接,否则我无法提出更精确的问题。有人能解释一下吗?另外,我正在使用TASM,如果有任何区别,请告诉我。另外,我在freedos上测试此功能。

更新1:

好的,感谢您的帮助,我相信我现在理解了中断的设置和行为。

设置: 我必须指定我希望缓冲区存在的ds:dx

我必须将ds:dx设置为20(这将设置缓冲区可以容纳的最大字符数)

我必须将ds:dx + 1设置为0(我认为这样设置了要读取的最小字符数)

实际调用int21 / AH = 0ah,它将进入ds:dx并解释预设字节。它会停止程序,同时等待输入

int21 / AH = 0ah将从ds:dx + 2 + n填充我的输入(其中n是包括'\r'的输入字符数)

现在我的问题是,我该如何做到这一点。我刚刚再次浏览了x86汇编语言参考文献,但还没有找到有用的信息。

我目前的代码:

           assume          cs:code,ds:code
code       segment
start:

           mov  ax,code ;moves code segment into reg AX
           mov  ds,ax   ;makes ds point to code segment

           mov  ah,0ah
           int  21h
           mov  ax,1234h  ;breakpoint

           mov  ah,9
           mov  dx,offset message
           int  21h

endNow:
           ;;;;;;;;;;ends program;;;;;;;;;;
           mov  ah,0  ;terminate program
           int  21h   ;program ends

message    db   'Hello world!!!',13,10,'$'
code       ends
           end  start
3个回答

10

这个DOS函数可以检索包含用户输入的缓冲区。请参见此表格。似乎该程序正在使用该调用来暂停执行,等待用户恢复程序。

编辑:我刚刚重新阅读了问题。我以为你只是在询问给定源中函数调用的作用。如果您想读取不超过20个字符的输入,首先需要内存来存储它。添加类似以下内容:

bufferSize  db 21  ; 20 char + RETURN
inputLength db 0   ; number of read characters
buffer      db 21 DUP(0) ; actual buffer

然后填充缓冲区:

mov ax, cs
mov ds, ax ; ensure cs == ds
mov dx, offset bufferSize ; load our pointer to the beginning of the structure
mov ah, 0Ah ; GetLine function
int 21h

如何转换为大写字母留给读者自行处理。


然后它的行为就像 int21 / AH = 1h,它会读取单个字符。我知道该中断将字符放入 AL 寄存器中,但我该如何找出字符缓冲区的位置? - user1707505
另外,我刚刚意识到。偏移表意味着实际字符数据从内存中返回数据存在的位置向后两个位或字节(可能是字节)开始。你有什么想法? - user1707505
是的,实际输入从DS:DX + 2开始。然而,该文件忽略了该输入并仅使用该函数来暂停执行。 - Michael McGuire
1
是的,我的最初问题是中断的行为方式,因为如果我只是问如何实现它,我不知道你刚才发布的内容是什么意思。非常感谢您的帮助。 - user1707505
应该是 mov dx,offset buffer 而不是 mov dx,offset bufferSize 吗?为什么前两个字节显示垃圾值?这是否意味着如果我要读取9个字符(包括字符串终止符),我必须再添加2个字符(前2个垃圾值)9 + 2 = 11个字节? - Ahtisham
@Ahtisham:不,DOS调用需要一个指向结构体开头的指针,因此它会读取[dx+0]和[dx+2..n],并写入[dx+1]。而不是[dx-2]和[dx-1]等,如果您传递了指向字符存储空间开头的指针,则需要这样做。那本来是一个有效的设计,但不是DOS选择的方式。 - Peter Cordes

3
那个描述说在调用中断之前,请将缓冲区的地址放入ds:dx。然后,该中断将填充缓冲区中读取的字符。在调用中断之前,缓冲区的第一个字节是缓冲区可以容纳的字符数,或者在您的情况下为20。我不理解缓冲区的第二个字节(输入到中断),因此我会将其设置为零。返回时,该字节将告诉您读取并放置到缓冲区中的输入字符数。

据我理解你的解释,可以在寄存器ds和dx中找到缓冲区的地址。 - user1707505
无关紧要的问题,给我一分钟思考上述内容。 - user1707505
有点像。 ds 是段寄存器; dx 是偏移量。你不会“找到”缓冲区;在调用中断之前,通过设置 dsdx 指向它来 提供 缓冲区。(在调用中断之前还需要设置缓冲区的前两个字节。缓冲区 - 以及其前两个字节 - 是中断的输入。)- Nemo 11分钟前 - Nemo
第二个字节是只输出,不是DOS调用的输入。另外,正如http://spike.scu.edu.au/~barry/interrupts.html#ah0a所指出的那样,在返回时,计数比缓冲区中写入的字节数少1,因为计数不包括最后的回车符。有关更多详细信息,请参见[缓冲输入的工作原理](https://dev59.com/zKbja4cB1Zd3GeqPneM6)。 - Peter Cordes

0
.model small
.stack 100h
.data 
    N db ?
    msg db 10,13,09,"Enter number of arrays---->$"
.code   
.startup
    mov ax,@data
    mov ds,ax
    call read_N;read N from console




    mov ah,4ch
    int 21h  

Read_N  proc
    ;get number of arrays from user

    push ax
    push dx

 readAgain:   

    mov ax,03h ;Clear screen
    int 10h

    mov dx,offset msg
    mov ah,09h
    int 21h

    call ReadNumber

    ;Inuput number must be in 2<=N<=10 bounery  
    cmp al,2
    js readAgain ;input out of boundary read again
    cmp al,10
    jg readAgain 
    mov N,al
    pop dx
    pop ax
    ret
Read_N endp

ReadNumber proc
    ;read decimal number 0-99 using 
    ;character by character in askii and conver in to decimal   
    ;return result in al
    xor ax,ax
    xor bx,bx
    xor dx,dx

    mov ah,01h
    int 21h

    sub al,'0'  ;conver in to decimal
    mov bl,al  

    mov ah,01h
    int 21h 
    cmp al,0dh  ;Exit if enter pressed
    jnz cont  
    mov al,bl
    jmp exit
  cont:
    sub al,'0'  ;conver in to decimal
    mov dl,al  

    xor al,al
    xor bh,bh
    mov cx,bx
  addnum:    
    add al,10
 loop addnum  

    add al,dl
  exit:   
  ret
 ReadNumber endp  

end           

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接