You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

8086汇编程序数字转单词写入文件时缓冲区覆盖问题求助

8086汇编输出缓冲区覆盖问题修复

问题描述

我编写的8086汇编程序,功能是将输入文件中的数字转换为对应单词,其余字符原样写入输出文件,但出现了输出缓冲区字符互相覆盖的问题。例如输入文件内容为0a,预期输出nulisa,实际输出为aulis。

原代码

.model small         
.stack 100h            

.data
    msgHelp        DB "Usage: program.exe <input_file> <output_file>$"    
    msgFileError   DB "Error: File not found or cannot be opened.$"    
    input db 200 dup (0)           
    output  db 200 dup (0)          
    skBuf   db 20 dup (?)  
    raBuf   db 200 dup (?) 
    words db "nulis", 0, "vienas", 0, "du", 0, "trys", 0, "keturi", 0, "penki", 0, "sesi", 0, "septyni", 0, "astuoni", 0, "devyni", 0
    wordOffsets dw 0, 6, 13, 16, 21, 28, 34, 39, 47, 55
    dFail   dw ?     
    rFail   dw ?     
    raBufPos dw 0    

.code

start:
    MOV ax, @data          
    MOV ds, ax         
    MOV di, offset raBuf    

    MOV bx, 82h             
    MOV si, offset input    

    cmp byte ptr es:[80h], 0 
    je help                  
    cmp es:[82h], '?/'       
    jne check_param          
    cmp byte ptr es:[84h], 13
    je help
    jmp check_param 

help:
    mov ah, 9              
    mov dx, offset msgHelp 
    int 21h                
    jmp programEnd       

check_param:
    cmp byte ptr es:[bx], 13 
    je next_filename         
    cmp byte ptr es:[bx], 32 
    je next_filename
    mov dl, byte ptr es:[bx] 
    mov [si], dl             
    inc bx                   
    inc si                   
    jmp check_param          

next_filename:
    inc bx 

    mov si, offset output    

output_filename_loop:
    cmp byte ptr es:[bx], 13 
    je found                

    mov dl, byte ptr es:[bx]
    mov [si], dl             
    inc bx                    
    inc si                    
    jmp output_filename_loop 

found:
    MOV ah, 3Dh              
    MOV al, 00      
    MOV dx, offset input
    INT 21h 
    JC file_error       
    MOV dFail, ax           

    MOV ah, 3Ch   
    MOV cx, 0               
    MOV dx, offset output      
    INT 21h                   
    JC file_error 
    MOV rFail, ax           

read:
    MOV bx, dFail
    CALL ReadBuf            
    CMP ax, 0               
    JE closeInput

    MOV cx, ax              
    MOV si, offset skBuf    

processLoop:
    MOV dl, [si]   
    CMP dl, '0'
    JB notDigit  
    CMP dl, '9'   
    JA notDigit 

    PUSH cx                  
    PUSH si
    PUSH di
    CALL ConvertDigitToWord  
    POP di                   
    POP si
    POP cx
    JMP skip 

notDigit:
    MOV [di], dl            
    INC di  
    INC raBufPos            

skip:
    INC si                  
    DEC cx                  
    JNZ processLoop         

writeOutput:
    MOV cx, raBufPos        
    MOV bx, rFail           
    MOV dx, offset raBuf    
    CALL WriteBuf
    MOV di, offset raBuf    
    MOV raBufPos, 0         
    JMP read                

file_error:
    MOV ah, 09h  
    MOV dx, offset msgFileError
    INT 21h
    jmp programEnd

closeOutput:
    MOV ah, 3Eh     
    MOV bx, rFail   
    INT 21h     
    JC file_error   

closeInput:
    MOV ah, 3Eh      
    MOV bx, dFail   
    INT 21h        

programEnd:
    MOV ah, 4Ch 
    MOV al, 0    
    INT 21h 

ConvertDigitToWord PROC
    SUB dl, '0'              
    MOV cl, dl

    MOV si, offset wordOffsets  
    MOV bx, cx 
    SHL bx, 1                
    ADD si, bx               
    MOV ax, [si]             
    ADD ax, offset words     
    MOV si, ax               

copyWord:
    MOV al, [si]             
    CMP al, 0  
    JE doneCopy              
    MOV [di], al             
    INC di                   
    INC si                   
    INC raBufPos             
    JMP copyWord    

doneCopy:
    RET  
ConvertDigitToWord ENDP

ReadBuf PROC
    MOV ah, 3Fh   
    MOV bx, dFail            
    MOV cx, 20               
    MOV dx, offset skBuf     
    INT 21h  
    RET       
ReadBuf ENDP

WriteBuf PROC
    MOV ah, 40h    
    MOV bx, rFail            
    MOV cx, raBufPos         
    MOV dx, offset raBuf     
    INT 21h  
    RET   
WriteBuf ENDP

END start

问题根源

核心错误在于调用ConvertDigitToWord前后错误地保存和恢复了di寄存器:

  • ConvertDigitToWord函数会将数字对应的单词写入raBuf,并通过INC di更新di的位置,使其指向单词末尾的下一个字节,方便后续字符继续写入。
  • 但原代码中调用该函数前PUSH di,调用后POP di,强行将di恢复到调用前的位置,导致后续字符会覆盖之前写入的单词开头部分。

比如输入0a时:

  1. 处理数字0,ConvertDigitToWord将nulis写入raBuf[0-4],di指向raBuf[5]。
  2. 但POP di后,di回到raBuf[0],处理字符a时直接将a写入raBuf[0],覆盖了原来的n。
  3. 最终raBuf中的内容变为aulis+a,输出时就出现了错误的aulis。

修复方案

移除processLoop中调用ConvertDigitToWord前后的PUSH di和POP di指令,保留di的更新结果:

processLoop:
    MOV dl, [si]   
    CMP dl, '0'
    JB notDigit  
    CMP dl, '9'   
    JA notDigit 

    PUSH cx                  
    PUSH si
    ; 移除 PUSH di
    CALL ConvertDigitToWord  
    ; 移除 POP di
    POP si
    POP cx
    JMP skip 

验证效果

修复后,输入0a时:

  1. 处理0,di从raBuf[0]更新到raBuf[5],raBufPos变为5。
  2. 处理a,写入raBuf[5],di更新到raBuf[6],raBufPos变为6。
  3. 写入输出文件的内容为nulisa,符合预期。

内容的提问来源于stack exchange,提问作者Denver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:54:50