我正在使用8086并且需要一个子程序来从文本文件中读取当前行,将内容放在字符串缓冲区中,除了换行符。我还要跟踪BX
上的线路长度(以字节为单位)。基本上我正在做的是:
while read_new_char_from_file() != (\r or \n or EOF) add it to the buffer, inc bx
then increment bx to account for the linefeed, and return
我运行了一些测试用例并且字节数正确,当字节为\n
时,循环停止,正如预期的那样。但是,字节似乎没有添加到我的字符串缓冲区中!子程序:
(FGETC
从FHANDLE
读取一个字符到CBUFF
(更新句柄)并且工作正常,但是可以找到here}。
FGETS PROC NEAR
PUSH AX ; (used by fgetc)
PUSH CX ; (used by fgetc)
XOR BX, BX ; clears our byte counter
CLD ; positive BF (used by STOSB)
LEA DI, SBUFFL ; pointer to the string buffer (used by STOSB)
FGETS_LOOP: ; read loop
CALL FGETC ; read a new char from the file to CBUFF
CMP AX, CX ; partial read (EOF)?
JNE FGETS_RET ; return
CMP CBUFF, 13 ; carriage return?
JE FGETS_RET_I ; return, increment byte count and handle to account for \r\n
CMP CBUFF, 10 ; line feed?
JE FGETS_RET_U ; return, increment byte count and handle to account for \n
MOV AL, CBUFF ; char to be written to buff
STOSB ; store string byte (increments DI)
INC BX ; increment the byte counter
JMP FGETS_LOOP ; loop
FGETS_RET_U: ; account for \n
INC BX ; increment byte counter
JMP FGETS_RET ; return
FGETS_RET_I: ; account for \r and \n
ADD BX, 2 ; increment byte count by 2
CALL FGETC ; increment fhandle (to skip \n)
FGETS_RET: ; return...
MOV AL, '$' ; add 'end of string' char to the buffer
STOSB ; ...
POP CX ; pops
POP AX ; ...
RET ; actually return
FGETS ENDP
测试案例的结果:
字符串缓冲区(40个大小并使用' x' s结束于' $'以便能够将其打印到标准输出并查看结果):
SBUFFL DB 40 DUP ('x'),'$' ; 4000 chars (4000 bytes)
文件内容(以\n
结尾的行):
4,5
500,-1000,0,250,-300
4,0,1,2,3
3,4,3,2
5,1,2,3,2,1
2,2,3
在文件开头用SBUFFL
调用FGETS
后,打印FHANDLE
(通过DOS int打印一个正常工作的字符串)的结果:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
表示从文件读取的字节未添加到缓冲区。但是,Turbo Debugger显示字节数(BX
)和停止条件(\n
)对于第一行的读取是正确的:
评论略有不同,只是代码中的差异是不必要的PUSH/POP DX
已删除,结果相同
调试器还会按预期在每次调用时显示STOSB
递增DI
。我尝试使用LEA DI, [SBUFF + 0]
,没有区别。不使用CLD
也没有任何区别。有点失去了。
答案 0 :(得分:0)
我怀疑DS
和ES
根本没有正确初始化。以下测试用例在这里工作正常(我没有改变你的功能):
.MODEL small
.STACK 1000h
.DATA
SBUFFL DB 40 DUP ('x'),'$'
FHANDLE DW ?
CBUFF DB ?
sample_txt db 'sample.txt',0
errtxt db 'Error.', 13, 10, '$'
.CODE
main PROC
mov ax, @data ; Initialise DS & ES
mov ds, ax
mov es, ax
mov ax, 3d00h ; fopen
lea dx, sample_txt
int 21h
jc errexit
mov [FHANDLE], ax
Loop: ; print fgets until "no string"
call FGETS
cmp byte ptr [SBUFFL], '$'
je Endloop
lea dx, SBUFFL
mov ah, 09h
int 21h
call crlf
jmp Loop
Endloop:
mov ah, 3Eh ; fclose
mov bx, [FHANDLE]
int 21h
mov ax, 4C00h
int 21h
errexit:
lea dx, errtxt
mov ah, 09h
int 21h
mov ax, 4C01h
int 21h
main ENDP
crlf PROC ; print line feed
push ds
push '$$'
push 0A0Dh
mov ax, ss
mov ds, ax
mov dx, sp
mov ah, 09h
int 21h
add sp, 4
pop ds
ret
crlf ENDP
FGETC PROC NEAR
PUSH BX ; pushs
PUSH DX
MOV AH, 03Fh ; Read from file
MOV BX, FHANDLE ; Found at fhandle
MOV CX, 1 ; Read 1 byte
LEA DX, CBUFF ; To cbuff
INT 21H ; Do it
POP DX ; pops
POP BX
RET ; return
FGETC ENDP
FGETS PROC NEAR
PUSH AX ; (used by fgetc)
PUSH CX ; (used by fgetc)
XOR BX, BX ; clears our byte counter
CLD ; positive BF (used by STOSB)
LEA DI, SBUFFL ; pointer to the string buffer (used by STOSB)
FGETS_LOOP: ; read loop
CALL FGETC ; read a new char from the file to CBUFF
CMP AX, CX ; partial read (EOF)?
JNE FGETS_RET ; return
CMP CBUFF, 13 ; carriage return?
JE FGETS_RET_I ; return, increment byte count and handle to account for \r\n
CMP CBUFF, 10 ; line feed?
JE FGETS_RET_U ; return, increment byte count and handle to account for \n
MOV AL, CBUFF ; char to be written to buff
STOSB ; store string byte (increments DI)
INC BX ; increment the byte counter
JMP FGETS_LOOP ; loop
FGETS_RET_U: ; account for \n
INC BX ; increment byte counter
JMP FGETS_RET ; return
FGETS_RET_I: ; account for \r and \n
ADD BX, 2 ; increment byte count by 2
CALL FGETC ; increment fhandle (to skip \n)
FGETS_RET: ; return...
MOV AL, '$' ; add 'end of string' char to the buffer
STOSB ; ...
POP CX ; pops
POP AX ; ...
RET ; actually return
FGETS ENDP
END main