如何在C语言中用int86与REGS结构体实现8086 DOS下文件读取显示
问题排查与修复方案
现有代码存在的问题
- 语法错误:
regs.h.al = 0x00行末尾缺少分号,regs_r.x.cx = 0x07;后的注释没有加//标记,编译阶段就会报错,实际运行的可能是未正确编译的旧版本代码 - 文件打开未做合法性校验:调用
open打开文件后没有判断返回值,如果目标文件不存在、路径错误、无读取权限,拿到的handle是非法值,后续所有中断调用都会失败 - 中断调用错误未校验:
int 21h调用后如果发生错误会置位进位标志,同时ax寄存器返回错误码,你当前没有做任何错误判断,无法定位是指针移动失败还是读文件失败 - 输出格式错误:
printf("DATA : %c", buff);中%c是单字符输出格式符,你传入的buff是字符数组的首地址,相当于把内存地址的低8位当做ASCII码输出,必然是乱码。如果要输出字符串应该用%s格式符 - 缓冲区无字符串结束符:DOS的
int 21h/3fh读文件功能只会把原始字节写入缓冲区,不会自动添加C语言字符串需要的\0结束符,直接用%s输出会读到缓冲区后面的随机内存值 - 读文件参数歧义:你当前设置读7个字节,如果文件实际内容不足7字节,实际读到的长度会存在
ax寄存器中,需要按实际长度处理
修复后的完整代码
#include <stdio.h> #include <conio.h> #include <fcntl.h> #include <dos.h> int handle; char buff[50]; void main(){ union REGS regs; union REGS regs_r; // 打开文件并校验 handle = open("text.txt", O_RDONLY); if(handle < 0){ printf("文件打开失败,请检查text.txt是否在当前目录"); getch(); return; } // 移动文件指针到开头 regs.x.bx = handle; regs.h.ah = 0x42; // LSEEK功能号 regs.h.al = 0x00; // 偏移基准:0=文件开头 regs.x.cx = 0; // 偏移量高16位 regs.x.dx = 0; // 偏移量低16位 int86(0x21, ®s, ®s); // 校验移动是否成功 if(regs.x.cflag){ printf("文件指针移动失败,错误码:%d", regs.x.ax); getch(); close(handle); return; } // 读取文件内容 regs_r.x.bx = handle; regs_r.x.cx = 49; // 最多读49字节,留1位放结束符 regs_r.h.ah = 0x3fh; // 读文件功能号 regs_r.x.dx = (unsigned int) buff; int86(0x21, ®s_r, ®s_r); // 校验读是否成功 if(regs_r.x.cflag){ printf("文件读取失败,错误码:%d", regs_r.x.ax); getch(); close(handle); return; } // 添加字符串结束符 buff[regs_r.x.ax] = '\0'; printf("DATA : %s", buff); close(handle); getch(); clrscr(); }
额外注意事项
- 请确保
text.txt文件和编译生成的exe程序在同一个目录下 - 如果需要读取更多内容,可以调整缓冲区大小和
cx寄存器的读入长度,注意始终预留1字节的位置存储字符串结束符 - 调试时可以打印
regs_r.x.ax的值确认实际读到的字节数,判断是否是文件本身为空的问题
内容的提问来源于stack exchange,提问作者umair mehmood
相关产品推荐
相关产品推荐

