Assembly x86 TASM任务管理程序:任务删除功能实现故障排查
TASM x86汇编任务管理程序删除功能异常问题
我用TASM开发x86汇编的任务管理程序,已经实现了任务添加和查看功能,但在做指定任务删除功能时出了问题。写了delete_task子程序,想通过处理换行符(13、10)和终止符$完成文件读写,结果执行删除后文件内容重复还带乱码。比如原来的任务列表是task1到task5,删除操作后内容变成原列表重复,还加了一堆乱码字符。
原程序代码
.model small .stack 100h .data sir db 80 dup('$') m2 db 'Introduceti sirul:$' m4 db '1. Add task', 13, 10, '$' m5 db '2. View tasks', 13, 10, '$' filename db 'tasks.txt',0 handle dw ? strLength dw ? t_handle dw ? newline db 13, 10, '$' ; 换行符 menuChoice db ? buffer db 2000 dup(0) .code mov ax,@data mov ds,ax mov ah, 9h mov dx, offset m4 int 21h mov ah, 9h mov dx, offset m5 int 21h mov ah, 1h int 21h mov menuChoice, al cmp menuChoice, '1' je add_task cmp menuChoice, '2' je view_tasks cmp menuChoice, '3' je delete_aux jmp end_program view_tasks: ; 打开文件只读 mov ah, 3Dh mov al, 0 mov dx, offset filename int 21h mov handle, ax ; 读取文件内容(仅读80字节) mov ah, 3Fh mov bx, handle mov dx, offset sir mov cx, 80 int 21h ; 逐字符显示内容 mov si, offset sir display_loop: cmp byte ptr [si], '$' je end_display mov ah, 02h mov dl, [si] int 21h inc si jmp display_loop end_display: ; 关闭文件 mov ah, 3Eh mov bx, handle int 21h jmp end_program delete_aux: cmp menuChoice, '3' jne view_tasks jmp delete_task add_task: ; 清空缓冲区 mov ah, 0Ah mov dx, offset sir int 21h ; 提示输入任务 mov ah, 9h mov dx, offset m2 int 21h mov bx,0 mov cx,80 mov ah,3fh mov dx,offset sir int 21h mov ah, 9h mov dx, offset sir int 21h ; 计算输入字符串长度 mov si, offset sir add si, 2 mov cx, 0 count_length: cmp byte ptr [si], '$' je end_count inc cx inc si jmp count_length end_count: mov strLength, cx ; 打开文件追加模式 mov ah, 3Dh mov al, 2 mov dx, offset filename int 21h mov handle, ax ; 定位到文件末尾 mov ah, 42h mov al, 2 mov bx, handle mov cx, 0 mov dx, 0 int 21h ; 写入任务内容 mov ah, 40h mov bx, handle mov dx, offset sir mov cx, strLength int 21h ; 写入换行符 mov ah, 40h mov bx, handle mov dx, offset newline mov cx, 2 int 21h ; 关闭文件 mov ah, 3Eh mov bx, handle int 21h jmp view_tasks delete_task: jmp view_tasks ; 删除后跳转到查看任务 end_program: mov ah,4Ch int 21h end
尝试实现的delete_task子程序
delete_task: ; 提示输入要删除的任务编号 mov ah, 9h mov dx, offset m_delete_prompt int 21h ; 读取用户输入的任务编号(转成数字) mov ah, 1h int 21h sub al, '0' mov bl, al ; 打开文件读写模式 mov ah, 3Dh mov al, 2 mov dx, offset filename int 21h mov handle, ax ; 读取文件到缓冲区 mov ah, 3Fh mov bx, handle mov dx, offset buffer mov cx, 2000 int 21h mov si, offset buffer mov di, si delete_loop: cmp byte ptr [si], '$' je end_delete mov al, [si] cmp al, 13 je check_next_char mov [di], al inc di inc si jmp delete_loop check_next_char: inc si ; 移动到下一个字符(LF) mov al, [si] cmp al, 10 je delete_task_found mov byte ptr [di], 13 inc di mov [di], al inc di inc si jmp delete_loop delete_task_found: ; 判断是否是要删除的任务 sub al, '0' cmp al, bl je skip_task jmp copy_task skip_task: ; 跳过要删除的任务 mov al, [si] cmp al, 13 jne skip_task jmp delete_loop copy_task: ; 保留当前任务内容 mov [di], al inc di inc si jmp delete_loop end_delete: ; 尝试截断文件 mov ah, 40h mov bx, handle mov dx, offset buffer sub di, offset buffer int 21h ; 关闭文件 mov ah, 3Eh mov bx, handle int 21h jmp view_tasks ; 数据段新增提示语 m_delete_prompt db 'Enter the task number to delete: $'
原有任务列表
task1 task2 task3 task4 task5
执行删除后的异常输出
task1 task2 task3 task4 task5 task1Útask2Útask3Útask4Útask5Ú ÿÿùtâ
问题原因及修复方案
核心问题分析
- 文件截断逻辑错误:用
ah=40h(写文件)无法截断文件,该功能仅能写入数据,截断需要先移动文件指针,再调用ah=4Ah(设置文件大小)。 - 任务编号判断逻辑错误:文件中仅存储任务内容和换行符,没有任务编号,你错误地将换行符LF(10)转成数字与用户输入对比,完全不匹配。
- 循环终止条件错误:文件内容没有
$终止符,用cmp byte ptr [si], '$'判断结束会读取缓冲区垃圾数据,导致乱码。 - 跳过任务逻辑漏洞:
skip_task仅跳过到下一个CR(13),未处理后续LF(10),且无边界判断,可能陷入死循环。
修复后的delete_task子程序
delete_task: ; 提示输入要删除的任务序号 mov ah, 9h mov dx, offset m_delete_prompt int 21h ; 读取用户输入的任务序号(转成数字) mov ah, 1h int 21h sub al, '0' mov bl, al ; bl = 要删除的任务序号 mov bh, 1 ; bh = 当前任务序号计数器,从1开始 ; 打开文件读写模式 mov ah, 3Dh mov al, 2 mov dx, offset filename int 21h mov handle, ax ; 读取整个文件到buffer,记录实际读取字节数 mov ah, 3Fh mov bx, handle mov dx, offset buffer mov cx, 2000 int 21h mov cx, ax ; cx = 实际读取字节数,作为循环上限 mov si, offset buffer mov di, si delete_loop: cmp cx, 0 je end_delete ; 读完所有字节,退出循环 mov al, [si] cmp al, 13 je check_lf ; 判断是否是要删除的任务内容 cmp bh, bl je skip_char ; 是要删除的任务,跳过该字符 mov [di], al ; 不是,复制到目标位置 inc di skip_char: inc si dec cx jmp delete_loop check_lf: ; 处理CR后面的LF inc si dec cx cmp cx, 0 je end_delete mov al, [si] cmp al, 10 jne not_lf ; 遇到完整的CR+LF,任务序号加1 cmp bh, bl jne keep_newline ; 不是要删除的任务,保留换行符 ; 是要删除的任务,跳过LF inc si dec cx inc bh jmp delete_loop keep_newline: ; 保留CR和LF mov [di], 13 inc di mov [di], 10 inc di inc si dec cx inc bh jmp delete_loop not_lf: ; 不是LF,把CR和当前字符复制回去 cmp bh, bl je skip_cr_char mov [di], 13 inc di mov [di], al inc di skip_cr_char: inc si dec cx jmp delete_loop end_delete: ; 将文件指针移到开头 mov ah, 42h mov al, 0 mov bx, handle mov cx, 0 mov dx, 0 int 21h ; 写入处理后的内容 mov ah, 40h mov bx, handle mov dx, offset buffer mov cx, di sub cx, offset buffer ; cx = 要写入的字节数 int 21h ; 截断文件到写入后的大小 mov ah, 4Ah mov bx, handle mov cx, 0 mov dx, di sub dx, offset buffer ; dx = 文件新大小 int 21h ; 关闭文件 mov ah, 3Eh mov bx, handle int 21h jmp view_tasks ; 数据段新增提示语 m_delete_prompt db '请输入要删除的任务序号: $'
额外修复:view_tasks模块读取限制
原代码仅读取80字节,会导致长内容显示不全,修改为读取整个文件并自动添加任务编号:
view_tasks: ; 打开文件只读 mov ah, 3Dh mov al, 0 mov dx, offset filename int 21h mov handle, ax ; 读取整个文件到buffer mov ah, 3Fh mov bx, handle mov dx, offset buffer mov cx, 2000 int 21h mov cx, ax ; cx = 读取的字节数 ; 显示内容并自动添加任务编号 mov si, offset buffer mov dl, '1' ; 初始任务编号 mov ah, 02h int 21h mov dl, '.' int 21h mov dl, ' ' int 21h display_loop: cmp cx, 0 je end_display mov al, [si] cmp al, 13 je display_cr ; 显示当前字符 mov dl, al mov ah, 02h int 21h inc si dec cx jmp display_loop display_cr: ; 显示换行符 mov dl, 13 int 21h mov dl, 10 int 21h inc si dec cx cmp cx, 0 je end_display ; 任务编号加1并显示 inc dl mov ah, 02h int 21h mov dl, '.' int 21h mov dl, ' ' int 21h jmp display_loop end_display: ; 关闭文件 mov ah, 3Eh mov bx, handle int 21h jmp end_program
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

