为何Turbo C编写的DOS程序在memset64000个int数组后崩溃?
解决MS-DOS 6.22下Turbo C++ 3.0 Mode 13h图形程序崩溃问题
问题场景
在VirtualBox的MS-DOS 6.22系统中,使用Turbo C++ 3.0编写Mode 13h图形程序时,出现memset无效、调用pokeb后程序崩溃的问题,目标是实现全屏白色填充。
原代码:
#include <stdlib.h> #include <conio.h> #include <stdio.h> #include <string.h> #include <dos.h> int main(void) { int *buf; unsigned int i; _AH = 0x0; _AL = 0x13; geninterrupt(0x10); buf = malloc(sizeof(int)*64000); memset(buf,15,64000); //can't figure out why memset does not work properly... for (i=0;i< (unsigned int)64000;i++){ buf[i] = 15; //trying to forcely set each byte to 0xf... pokeb(0xA000,i,buf[i]); //outputting to VGA } getch(); free(buf); return(0); }
错误原因分析
缓冲区类型不匹配
Mode 13h的VGA显存是320×200分辨率,每个像素占1字节,总大小64000字节。你使用int* buf(int在Turbo C中为2字节),导致:malloc(sizeof(int)*64000)分配了128KB内存,远超需求;memset(buf,15,64000)仅能填充前64KB(32000个int),且每个int的两个字节都会被设为0x0f,不符合单像素单字节的逻辑;- 循环中
buf[i]访问的是第i个int(对应显存的第2i和2i+1字节),逻辑完全错位。
BIOS中断调用不规范
直接给_AH、_AL赋值后调用geninterrupt并非Turbo C的标准用法,可能引发寄存器冲突,导致视频模式切换异常或程序崩溃。未检查内存分配结果
若malloc失败返回NULL,后续对buf的操作会直接触发崩溃。未恢复文本模式
程序退出后停留在图形模式,会导致DOS界面乱码,同时可能残留异常状态。
修正后的代码
方案1:使用缓冲区填充
#include <stdlib.h> #include <conio.h> #include <dos.h> #include <string.h> int main(void) { unsigned char *buf; unsigned int i; union REGS regs; // 切换到Mode 13h(320×200 256色) regs.x.ax = 0x0013; int86(0x10, ®s, ®s); // 分配显存大小的缓冲区,检查分配结果 buf = (unsigned char*)malloc(64000); if (!buf) { // 分配失败,恢复文本模式后退出 regs.x.ax = 0x0003; int86(0x10, ®s, ®s); return 1; } // 用memset一次性填充所有像素为白色(颜色值15) memset(buf, 15, 64000); // 将缓冲区内容写入VGA显存 for (i = 0; i < 64000; i++) { pokeb(0xA000, i, buf[i]); } // 等待按键 getch(); // 释放内存 free(buf); // 恢复文本模式(0x03) regs.x.ax = 0x0003; int86(0x10, ®s, ®s); return 0; }
方案2:直接操作显存(更高效)
不需要缓冲区,直接循环写入显存:
#include <conio.h> #include <dos.h> int main(void) { unsigned int i; union REGS regs; // 切换到Mode 13h regs.x.ax = 0x0013; int86(0x10, ®s, ®s); // 直接填充显存为白色 for (i = 0; i < 64000; i++) { pokeb(0xA000, i, 15); } getch(); // 恢复文本模式 regs.x.ax = 0x0003; int86(0x10, ®s, ®s); return 0; }
关键修复点说明
- 将缓冲区类型改为
unsigned char*,匹配Mode 13h单像素单字节的结构; - 使用
union REGS配合int86函数规范调用BIOS中断,保证寄存器操作安全; - 增加
malloc结果检查,避免空指针操作; - 程序退出前恢复文本模式,避免界面乱码;
- 利用
memset高效完成批量字节赋值,替代冗余的手动循环。
内容的提问来源于stack exchange,提问作者SlickSpore
相关产品推荐
相关产品推荐

