【问题标题】:How to read a character from the keyboard and save it to a file in DOS assembly?如何从键盘读取字符并将其保存到 DOS 程序集中的文件中?
【发布时间】:2013-02-14 23:00:05
【问题描述】:

我正在使用 3Ch 函数创建文件并使用 40h 函数保存字符(我读过它here

我不明白如何将读取字符放入DS:DX

这是我的代码:

org 100h
bits 16

section .data
    file DB 'file.txt',0

section .bss
    file_handle resw 1

; CREATE FILE
section .text
    mov DX, file 
    mov CX, 0000h
    mov AH, 3Ch
    int 21h

; START INPUT
INPUTSTART:
    mov AH,01h
    int 21h

    ; SAVE INPUT TO FILE
    mov SI, file_handle
    mov BX, [SI]
    mov CX, 0001h
    mov AH, 40h
    int 21h

   jmp INPUTSTART

    mov AH,4Ch
    int 21h

如您所见,程序旨在循环工作并写入与用户类型一样多的字符。请帮助获取 40h 函数的文件句柄并将数据放入 DS:DX

【问题讨论】:

  • 你用的是什么汇编程序?
  • 下面的两个答案都帮助我创建了正确的 ASM 代码。两者都需要一些改进,所以我不能接受其中任何一个。我给了+1。谢谢。
  • 请接受其中任何一个,这样问题就会被标记为已接受,并帮助其他人找出哪些问题被接受,哪些问题不被接受。很多时候你会在 SO 中收到很多有用的答案,然后你只需要选择对你最有帮助的答案。
  • 你有一个 hazardous 错误,它是读取而不是读取 ;)

标签: assembly input x86 dos


【解决方案1】:

根据代码的语法,我猜您正在使用 NASM 并尝试创建一个 .COM 程序。

.COM 程序的代码从文件的最开头开始,也没有将文件划分为逻辑部分,因此您不能先放置数据部分(例如 .data 或 .bss),它不会甚至定义这样的部分也没有多大意义。

因此,您的代码应如下所示:

org 100h
bits 16

; code begins here
; then goes data

org 100h
bits 16

jmp start
; here goes data
start:
; here goes the rest of code

接下来,函数 3Ch 在AX 中返回一个文件句柄。您可以使用此句柄对文件执行进一步的操作(例如读取、写入、关闭)。您的代码没有将这个句柄隐藏在file_handle 中,我猜它就是为此目的而定义的,它通过用mov AH,01h 覆盖AX 的值来丢弃它。你需要解决这个问题。

在程序结束时,您必须使用函数 3Eh 关闭文件。如果您不这样做,该文件可能最终只包含已写入其中的一部分数据,在您重新启动 PC 之前,该文件可能无法访问,并且您也可能无法打开(或创建)更多文件如果您积累了足够多的未关闭文件句柄。所以,最后关闭文件。

至于将字符保存在文件中,没有什么可以阻止您定义一个字节变量,比如key,将AL 存储到其中,然后将key 的地址传递给函数40h,例如:

...
mov AH,01h
int 21h
mov [key], AL

; SAVE INPUT TO FILE
mov BX, [file_handle]
mov DX, key
mov CX, 0001h
mov AH, 40h
int 21h
...
file_handle dw 0
key db 0
...

另外,不要忘记指定一些键来打破您现在在程序中的无限循环。

【讨论】:

  • 谢谢。我将 NASM 用于 COM 文件。我的代码头看起来像这样(并且工作完美):org 100h bits 16 section .data file db 'file.txt',0 character_read db 0 section .bss file_handle resw 1
【解决方案2】:

其实你并没有把字符放入ds:dx,而是你使用ds:dx引用字符或任何数据所在的内存地址存储,在 Intel 语法中它会是 [ds:dx](但 dx 不能用于内存寻址)。

所以,你需要做的是:用 DOS 中断 21h / ah = 01h 将从键盘读取的值存储在 al 中返回到某个内存地址,然后用 ds:dx 引用该内存地址。

在您的代码中,您根本不存储文件句柄,并在写入文件调用之前从变量 file_handle 加载 0,因为这就是您初始化它的方式。然后你尝试从ds:0 读取文件句柄(因为si 等于0),这根本没有意义。您需要对文件句柄做的就是存储它(在文件创建/截断后在ax 中返回值)并始终将其加载到后续int 21h 引用同一文件的相关寄存器(写入文件,从文件、关闭文件等)。

因此,通过下面的修复它应该可以工作(未测试)。我还将函数调用参数按照 Ralf Brown 的中断列表使用的顺序进行了整理,以便于理解。

.section data
file db 'file.txt',0
character_read db 0

...

% create file:
    mov ah,3Ch             % create or truncate a file
    mov dx,file            % ds:dx points to ASCIIZ filename
    xor cx,cx              % file attributes.
    int 21h

    mov [file_handle], ax  % file handle must be stored in memory or in a register!

INPUTSTART:
    mov ah,1               % read character from STDIN, with echo.
    int 21h
    mov [character_read], al  % store the ASCII code to memory.

    % unless you want to loop eternally, you can check the ASCII code and exit.

    cmp al,20h             % space.
    je  EXIT

    mov ah,40h             % write to file or device
    mov bx,[file_handle]   % file handle is just a number.
    mov cx,1               % number of bytes to write.
    mov dx,character_read
    int 21h

    jmp INPUTSTART

EXIT:
    % here you can add some clean-up code, if needed.

    mov ah,3Eh             % close file.
    mov bx,[file_handle]   % here you need the file handle again.
    int 21h

    mov ah,4Ch
    int 21h

【讨论】:

  • 谢谢,经过一些修改,代码可以工作了。我也使用了 Alexey 的代码。我使用 NASM。
猜你喜欢
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-11
  • 2018-01-17
  • 2021-07-03
  • 2019-08-23
  • 2010-10-26
相关资源
最近更新 更多