如果你正在学 C 语言,八成听过 DEV-C++ 这个上古神器;如果你被课程设计逼着要写个带界面的程序,大概率也已经搜到了 ege 这个图形库。我帮不少同学配过 ege19.01 的环境,发现一半以上的人卡在同一个地方:库文件不会选、链接参数不会写,换到 VsCode 后又不知道去哪配置。这篇文章把我踩过的坑一次性理清楚,从 DEV-C++ 和 VsCode 两条路分别讲,保证你跟着操作十分钟能跑起来。
1. ege19.01 是什么:从 Turbo C 到 Windows 图形界面的桥梁
1.1 你学的 C 只有黑窗口,但课程设计需要图形界面
学校教 C 语言,基本都是在控制台里敲 printf、scanf,输出一片黑底白字。可一旦到了课程设计阶段,老师突然让你做个"学生成绩管理系统""贪吃蛇游戏"甚至"画图板",控制台那套东西瞬间就不够用了。直接用 Windows API 写窗口,学习曲线太陡——光是 CreateWindow 那一堆参数就足够劝退新手。
ege(Easy Graphics Engine)就是为解决这个尴尬而生的。它是一个开源的 C++ 图形库,核心设计思路是:让你用接近 Turbo C 时代 BGI 图形库的写法,快速在 Windows 窗口里画点、画线、画圆、显示图片、处理鼠标键盘事件。你不需要理解 GDI 内部机制,几行代码就能出一个带窗口的图形程序。
1.2 ege 能做什么,边界在哪里
ege19.01 这个版本我用下来,常见的 2D 需求基本都覆盖了:
- 基本绘图:点、线、矩形、圆、椭圆、扇形、填充色、背景色
- 文字显示:outtextxy 在指定坐标输出字符串
- 图片加载:可以读 BMP、PNG、JPG 等常见格式并贴到窗口上
- 鼠标键盘:MouseHit、getmouse、keystate 等 API 做交互
- 双缓冲机制:BeginBatchDraw / FlushBatchDraw 配合,动画不闪烁
- 音频:配合其它库能播放音乐(不过这块我一般直接用 Windows 的 PlaySound,少一点依赖)
它的边界也很明显:只支持 Windows、只适合 2D 轻量级图形程序、没有现成的 UI 控件(按钮、输入框都得自己画)。如果你要做 3D 游戏、复杂软件界面,或者需要跨平台,那该用 Unity、Qt 或者 SDL,而不是 ege。但作为教学和课程设计工具,它足够轻、足够稳,这也是为什么网上大量教程和实验课都指定它。
注意:ege 是一个库,不是一个独立软件。它需要配合编译器使用,所以你才会看到"DEV-C++ 配 ege""VsCode 配 ege"这种说法。配环境这件事,本质上就是告诉编译器三件事:头文件去哪找、库文件去哪找、链接的时候带上哪个库。
2. DEV-C++ 配 ege19.01:一次点明白,连库文件名一起讲清
2.1 解压与放置:include、lib、dll 分别放哪
先说一下整体思路。DEV-C++(我推荐 Orwell Dev-C++ 5.11,网上大多数教程也是按这个版本写的)自带 MinGW 编译器,配置 ege 的核心就两步:让编译器能找到头文件和库文件,让链接器知道要链哪个库。
下载 ege19.01 后,你会得到一个压缩包,解压后里面有三个关键目录:include、lib、dll。我习惯把整个压缩包解压到一个固定的地方,比如D:\ege19.01,不放 C 盘系统目录,免得权限问题。目录结构大致是这样:
D:\ege19.01\ include\ graphics.h ege.h ... lib\ libgraphics.a libgraphics64.a ... dll\ ege.dll ege64.dll README.txt这里我要专门提醒一句:不同网络来源的 ege 压缩包,文件名可能有差异,有的叫 libgraphics.a,有的叫 libEGE.a,有的把 64 位库单独放在 x64 子目录里。一切以你实际解压出来的文件名为准,README.txt 里通常写得很清楚。
2.2 识别库文件:确定你该用哪一个链接参数
这是很多人配置失败的第一道坎。MinGW 编译器在链接静态库时,-l参数会去找libxxx.a这样的文件。比如你看到 lib 目录下有一个libgraphics.a,那链接参数就是-lgraphics;如果文件叫libEGE.a,参数就是-lEGE(Windows 下大小写在很多时候不敏感,但建议按实际大小写来)。
还有一个关键点:DEV-C++ 5.11 自带的编译器是 32 位的 TDM-GCC 4.9.2,所以它只能链接 32 位的库文件。如果你下载的压缩包里同时有 libgraphics.a 和 libgraphics64.a,DEV-C++ 里必须选libgraphics.a(32 位),别拿 64 位的去试。
如果你的包里只有一个 64 位库文件,也不是完全没办法:你可以单独给 DEV-C++ 配置 64 位编译器,但这个操作比较折腾,我建议直接换 VsCode 那条路,或者下载一个明确标注"for Dev-C++"的 ege 版本。
2.3 全局配置与单个工程配置:两个地方的参数都要加
配置路径分两个层次,建议按"头文件和库目录做全局、链接参数做工程级"来分工。
第一步:配置头文件和库目录
打开 DEV-C++,菜单栏点"工具 -> 编译器选项",在弹出的窗口里切到"目录"标签页:
- "C++ 包含文件"里面添加
D:\ege19.01\include - "库文件"里面添加
D:\ege19.01\lib
这一步做完,编译器就能找到 graphics.h 和静态库文件本身。
第二步:配置链接参数
我比较推荐在单个工程里配置链接参数,而不是全局配置。原因是链接参数会跟着所有工程生效,如果你的其它 C 程序不打算用 ege,加了反而会让编译器多找一次库,有时还会报无关的错。
具体操作:在 DEV-C++ 里打开你的工程(如果你只是随便写个单文件测试,就新建一个"Helloworld 项目"或者直接新建 .cpp 文件),菜单栏点"项目 -> 项目属性"(有的版本叫"工程选项"),切到"参数"标签页,在"连接器"那一栏加上:
-lgraphics -lgdi32 -limm32 -lmsimg32 -lole32 -loleaut32 -luuid如果你的库文件名不是 libgraphics.a,把-lgraphics换成对应的名字(比如-lEGE)。后面那一串-lgdi32 -limm32 ...是 ege 依赖的 Windows 系统库,少了它们链接时会报 undefined reference,这个参数组合是 ege 文档里明确写的,不要省。
还有一个更粗暴但不容易出错的办法:不猜库文件名,直接把库文件的完整路径写在连接器参数里。比如:
D:\ege19.01\lib\libgraphics.a -lgdi32 -limm32 -lmsimg32 -lole32 -loleaut32 -luuidgcc(DEV-C++ 底层就是 gcc)允许直接把 .a 文件当作输入文件处理,这样完全绕开了-l名字匹配的问题。这个技巧在 VsCode 里同样能用,后面我会再提到。
2.4 复制 dll:运行时最常见的第一个报错
编译通过只是第一步。ege19.01 是动态链接的,也就是说你的 exe 运行的时候需要一个叫 ege.dll 的动态库文件。如果这个文件不在 exe 同目录,也不在系统 PATH 里,双击运行时就会弹"由于找不到 ege.dll,无法继续执行代码"。
解决办法很简单:把D:\ege19.01\dll\ege.dll复制到你的 exe 所在目录。如果你用 DEV-C++ 的"运行"按钮,exe 一般生成在工程目录下的bin\Debug或者bin\Release里,把 dll 复制到那个目录就行。
提醒:如果你的程序编译成了 64 位,那运行时需要的可能是 ege64.dll 而不是 ege.dll,具体以 README 说明为准。DEV-C++ 5.11 默认是 32 位,用 ege.dll 基本没问题。
3. VsCode 配 ege19.01:从编辑器到编译器的完整链路
3.1 为什么 VsCode 比 DEV-C++ 麻烦:三件套各管一摊
VsCode 本质上是一个文本编辑器,它不负责编译。你要让它编译 C++ 程序,需要凑齐三样东西:编译器(MinGW-w64 或其它 gcc)、Microsoft 的 C/C++ 扩展(负责代码高亮和智能提示)、以及 .vscode 目录下的三个 JSON 配置文件(tasks.json、launch.json、c_cpp_properties.json)。
很多人一看到三个 JSON 文件就头大,但其实逻辑很简单:
- tasks.json:告诉 VsCode"编译时执行什么命令",对应你在终端里手动敲 g++ 指令
- launch.json:告诉 VsCode"按 F5 调试时启动哪个 exe、用哪个调试器"
- c_cpp_properties.json:只给代码提示功能看,告诉 IntelliSense 头文件在哪、编译器是哪个,不参与实际编译
3.2 编译器、插件、三个 JSON 文件的分工逻辑
先说编译器。我推荐单独安装一个 MinGW-w64,不要用 DEV-C++ 自带的那套(32 位太老,配 VsCode 只能将就)。现在网上比较主流的来源是 MSYS2、WinLibs、w64devkit。我自己的习惯是用 WinLibs 的独立压缩包,解压即用,不需要额外装环境。
以我装在D:\mingw64为例,里面关键的路径是:
D:\mingw64\bin\g++.exe D:\mingw64\bin\gdb.exeVsCode 扩展我只装 Microsoft 官方的 C/C++ 插件(扩展名就叫"C/C++",发布者是 Microsoft)。装完这个插件,你的 .cpp 文件才会出现 IntelliSense,也才能用 F5 调试。
安装完扩展后,打开一个文件夹作为工作区(比如D:\ege_demo),在里面建一个main.cpp。按下Ctrl+Shift+P,输入C/C++: Edit Configurations (JSON),VsCode 会帮你生成一个默认的 c_cpp_properties.json,我们先放着,后面再改。
3.3 tasks.json:把编译命令写明白,-lgraphics 还是直接写库路径
编译这件事,tasks.json 里要写清楚 g++ 需要执行的完整命令。我直接给你一份可用的配置,把其中编译器路径和 ege 路径换成你自己的:
{ "version": "2.0.0", "tasks": [ { "type": "cppbuild", "label": "EGE 编译", "command": "D:/mingw64/bin/g++.exe", "args": [ "-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe", "-I", "D:/ege19.01/include", "-L", "D:/ege19.01/lib", "-lgraphics", "-lgdi32", "-limm32", "-lmsimg32", "-lole32", "-loleaut32", "-luuid", "-mwindows" ], "options": { "cwd": "${fileDirname}" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true }, "detail": "用 g++ 编译 ege 程序" } ] }逐条解释一下:
command是 g++ 的绝对路径,注意斜杠方向在 JSON 里用正斜杠或双反斜杠都行,D:/mingw64/bin/g++.exe这种写法最省事-I指定头文件目录,后面跟 ege 的 include 路径-L指定库文件搜索目录,后面跟 ege 的 lib 路径-lgraphics是链接库名,如果你的库文件不叫这个,参照 2.2 节的方法换成实际名字-mwindows表示这是一个 Windows GUI 程序,编译出来的 exe 不会带黑色控制台窗口
如果你不想纠结-lgraphics名字对不对,直接把库文件全路径加进去,去掉-L "D:/ege19.01/lib"和-lgraphics,换成:
"D:/ege19.01/lib/libgraphics.a"这个完整路径被 g++ 当成一个输入文件直接参与链接,不依赖-l的命名规则。这是我给新手推荐的做法,因为它少一个不确定因素——你只需要确保路径和文件名跟实际解压出来的一致就行。
3.4 c_cpp_properties.json:消掉红色波浪线
如果配置完 tasks.json,编译虽然能过,但编辑器里一直飘着红色波浪线,提示graphics.h找不到,那就是 c_cpp_properties.json 的问题。它是给 IntelliSense 智能提示用的,不参与真实编译。
在生成的文件基础上,重点改动 includePath 和 compilerPath:
{ "configurations": [ { "name": "Win64", "includePath": [ "${workspaceFolder}/**", "D:/ege19.01/include" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "compilerPath": "D:/mingw64/bin/g++.exe", "cStandard": "c17", "cppStandard": "cpp17", "intelliSenseMode": "windows-gcc-x64" } ], "version": 4 }includePath里加了D:/ege19.01/include之后,graphics.h 的波浪线就会消失,ege 的 API 也会有补全提示。intelliSenseMode里的windows-gcc-x64要和你安装的 MinGW 位数一致,如果你装的是 32 位编译器,改成windows-gcc-x86。
3.5 launch.json:也能用 F5 断点调试
编译能过、提示也正常之后,按 F5 还不能调试,因为 VsCode 不知道启动哪个调试器、哪个 exe。在 .vscode 目录下创建 launch.json:
{ "version": "0.2.0", "configurations": [ { "name": "EGE 调试", "type": "cppdbg", "request": "launch", "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [], "externalConsole": true, "MIMode": "gdb", "miDebuggerPath": "D:/mingw64/bin/gdb.exe", "setupCommands": [ { "description": "为 gdb 启用整齐打印", "text": "-enable-pretty-printing", "ignoreFailures": true } ], "preLaunchTask": "EGE 编译" } ] }注意preLaunchTask的值"EGE 编译"必须和 tasks.json 里的label完全一致,否则按 F5 时会提示找不到任务。externalConsole设为 true 是建议,因为 ege 程序会弹图形窗口,用外部终端展示控制台输出更直观,不容易跟 VsCode 集成终端打架。
小技巧:调试阶段我把 tasks.json 里的
-mwindows临时删掉,这样程序会保留一个黑色控制台窗口。printf 调试往窗口输出,图形窗口正常显示,非常方便。确认没问题之后再加回-mwindows,发布时就没有那个黑框了。
4. 第一个能跑的程序:画圆、鼠标跟随、动画一锅端
4.1 最小程序:从 initgraph 到 closegraph
配置完成后,写第一个程序。新建main.cpp,内容如下:
#include <graphics.h> int main() { initgraph(640, 480); // 创建一个 640x480 的图形窗口 setbkcolor(WHITE); // 设置背景色为白色 cleardevice(); // 用背景色清屏 setcolor(BLACK); // 设置当前绘制颜色为黑色 circle(320, 240, 100); // 在窗口中心画一个半径 100 的圆 getch(); // 等待按键 closegraph(); // 关闭图形窗口 return 0; }initgraph打开图形窗口,closegraph释放资源。中间夹着的就是你的绘图逻辑。getch()的作用是让窗口停住,不然程序一跑完窗口就关了。
这个程序在 DEV-C++ 里直接按 F11(编译运行)或 Ctrl+F10,在 VsCode 里按 Ctrl+Shift+B 编译、然后运行生成的 exe,或者按 F5 一条龙。能看到一个 640x480 的白底窗口,中间一个黑色圆圈,说明环境已经完全打通。
4.2 鼠标和键盘交互的写法
静态图形没什么意思,ege 真正的价值是交互。下面这个程序让一个圆跟着鼠标走:
#include <graphics.h> int main() { initgraph(640, 480); int x = 320, y = 240; while (true) { if (MouseHit()) { mouse_msg msg = getmouse(); if (msg.is_move()) { x = msg.x; y = msg.y; } } cleardevice(); setcolor(EGERGB(255, 100, 100)); circle(x, y, 30); delay_fps(60); // 控制帧率约 60fps } closegraph(); return 0; }ege 的鼠标 API 设计得很贴心:MouseHit()判断有没有鼠标消息,getmouse()取出一条消息,msg.is_move()判断是不是移动消息,msg.x / msg.y拿到鼠标坐标。EGERGB(r, g, b)是 ege 的颜色宏,比 Windows 的RGB宏在部分场景下更省心。
按 ESC 退出的写法也很简单,在循环开头加一句:
if (keystate(VK_ESCAPE)) break;VK_ESCAPE是 Windows 标准虚拟键码,ege 的keystate函数可以直接查状态。如果你只想按一下响应一次,而不是按住持续响应,用kbhit()配合getch()或者vkey()更合适,看具体需求。
4.3 帧动画与双缓冲:别再用 while+清屏硬拖了
很多第一次用 ege 的人,写动画会在循环里不断cleardevice()再画,结果画面狂闪。这是因为每次cleardevice()都会真正刷新屏幕缓冲区,超出垂直同步频率就会出现撕裂感。正确做法是用 ege 的双缓冲接口。
双缓冲的逻辑一句话:所有绘图操作先画到一块内存画布上,画完之后一次性刷到屏幕上。中间没有中间帧暴露给用户,视觉上就非常顺滑。ege 把这套封装成了三个函数:BeginBatchDraw()、FlushBatchDraw()、EndBatchDraw()。
下面是一个简单的圆周运动动画:
#include <graphics.h> #include <math.h> int main() { initgraph(640, 480); int cx = 320, cy = 240; double angle = 0; BeginBatchDraw(); while (!keystate(VK_ESCAPE)) { int x = cx + static_cast<int>(150 * cos(angle)); int y = cy + static_cast<int>(100 * sin(angle)); cleardevice(); setcolor(EGERGB(255, 200, 50)); circle(x, y, 30); FlushBatchDraw(); angle += 0.05; delay_fps(60); } EndBatchDraw(); closegraph(); return 0; }这里cos和sin需要<math.h>,注意 ege 的坐标系统是屏幕上 x 向右、y 向下,跟数学课本上的直角坐标不一样,但反正圆周运动画出来视觉上还是圆,不用过度纠结。
提示:
BeginBatchDraw()和EndBatchDraw()之间不要放getch()这类阻塞函数,某些版本会导致画面不刷新。需要等待用户按键时,可以先FlushBatchDraw()再阻塞。
5. 两套环境怎么选:我的实际经验
5.1 上课/快速验证选 DEV-C++
DEV-C++ 最大的优势就是开箱即用。编译器内置、界面简单、菜单点几下就能配好,非常适合教学场景。我帮学生配环境时,如果只是课堂上跑例题、交个作业,我会直接推荐 DEV-C++。
它的缺点也很明显:编辑器功能太老,代码补全几乎等于没有,拼错一个成员函数名要编译才能发现;自带的 gcc 4.9.2 年代久远,C++11 支持一般;调试器难用到我不想多说。所以它适合"跑通"和"交作业",不适合"认真开发"。
5.2 课程设计/长期项目选 VsCode
如果你要做一个正经的课程设计,或者打算以后继续写 C++,我建议一上来就用 VsCode。虽然配置要花半小时,但你换来的是:
- IntelliSense 补全,写
initg直接带出initgraph - F5 断点调试,可以在
circle调用前后暂停,看变量值 - 终端集成,编码、编译、运行的反馈都在一个界面里
- 后续要不要装 Code Runner、Git 插件、Markdown 插件,都很自由
VsCode 的麻烦是要自己写 JSON 配置,但对新手来说,照着上面 3.3、3.4、3.5 三节抄一遍就能跑,成本再高也就一次。
5.3 32 位与 64 位的匹配问题:配置里最容易翻车的点
两套环境放一起,最容易被忽略的问题就是位数匹配。
DEV-C++ 5.11 自带 32 位编译器,VsCode 里装 WinLibs 的 MinGW-w64 大多是 64 位。如果你的 ege 压缩包里给出了 libgraphics.a(32 位)和 libgraphics64.a(64 位)两个文件,那:
- DEV-C++ 用
libgraphics.a,链接参数-lgraphics - VsCode 用
libgraphics64.a,链接参数-lgraphics64
运行时 dll 同理:32 位程序一般匹配 ege.dll,64 位程序匹配 ege64.dll(或者需要改名,看 README)。
这个规则不是 ege 特有的,任何 Windows 本机库都这样。一次我在帮同学排查问题,他用 DEV-C++ 的编译器编译,却在链接时顺手选了 64 位库文件,结果疯狂报 undefined reference,折腾半天才发现是位数不匹配。先确认位数,再动配置,顺序反过来会让你怀疑人生。
我来做一个直观对比:
| 对比项 | DEV-C++ 5.11 | VsCode + MinGW-w64 |
|---|---|---|
| 初始配置成本 | 低,菜单点几下 | 中高,要写 JSON |
| 自带编译器位数 | 32 位 | 64 位(可自行选择) |
| 智能补全 | 弱 | 强 |
| 调试体验 | 老式 GDB,勉强能用 | 断点、变量监视都顺手 |
| 适合场景 | 课堂例题、快速验证 | 课程设计、长期项目、后续深入学习 |
6. 高频报错排查清单:直接抄就好
6.1 找不到 graphics.h:include 路径没加
报错长这样:fatal error: graphics.h: No such file or directory。原因只有一个:编译器不知道去哪找头文件。解决方法是检查你配置的 include 路径(也就是 2.3 节或 3.3 节里的-I参数),确认路径指向实际存在的D:\ege19.01\include目录,并且目录下的文件名确实叫graphics.h,不是graphics.h.txt。
6.2 undefined reference:库没链上,或链的顺序不对
这种报错信息很长,通常是一大串undefined reference to 'xxx',看着吓人,但原因就几类:
- 完全没写链接参数:检查 tasks.json 或 DEV-C++ 工程参数里有没有
-lgraphics - 库文件没找到:检查
-L路径是否正确、库文件名是否匹配 - 位数组不匹配:32 位程序链了 64 位库,或者反过来,照样报 undefined reference
- 链接顺序问题:gcc 链接时
-l参数要放在源文件之后。比如g++ main.cpp -lgraphics没问题,但g++ -lgraphics main.cpp在某些情况下会直接漏链。建议所有-l都放在命令末尾
6.3 找不到 ege.dll:运行时路径问题
编译过了,运行时报"找不到 ege.dll",这个在 2.4 节已经讲过。补充一个扩展办法:把 ege.dll 所在目录加到系统 PATH 环境变量里,或者直接把 dll 复制到 C:\Windows\System32 下。前者更干净,后者最快,但系统目录攒太多第三方 dll 不是一个好习惯,我仍然建议复制到 exe 同目录。
6.4 控制台不显示 printf 输出:-mwindows 的两面性
配好环境后发现程序弹了图形窗口,但看不到 printf 的输出,别慌,是你编译时带了-mwindows。这个参数把 PE 头的子系统标记成 GUI,Windows 默认不分配控制台窗口,所以 printf 的输出"消失"了。解决办法按 3.5 节提示的:调试阶段去掉-mwindows,发布时再加上。
6.5 中文乱码:编码方案从源头统一
DEV-C++ 5.11 默认用 GBK 编码,VsCode 默认 UTF-8。同一个outtextxy(100, 100, "你好"),在 DEV-C++ 里正常,在 VsCode 里乱码,反之亦然。处理方法有两个:
- 统一源码编码:在 VsCode 里点右下角编码按钮,改成 GBK,跟 DEV-C++ 一致
- 内容用宽字符:
outtextxy(100, 100, L"你好"),配合 ege 的宽字符重载。但并不是所有版本都支持得一样好,建议以测试为准
我自己的习惯是:人在 DEV-C++ 就全 GBK,人在 VsCode 就全 UTF-8,避免混合。
6.6 DEV-C++ 的 gcc 太老,新特性代码编译不过
DEV-C++ 5.11 自带的 gcc 4.9.2 对 C++11 支持得还行,但对 C++14/17 的新特性就很勉强。如果你把 VsCode 里编译通过的代码贴回 DEV-C++ 编译报错,先想想是不是用了auto推导复杂类型、结构化绑定、std::optional这类特性。解决办法要么换编译器,要么把要交的作业提前确认一下老师指定的 IDE 版本。这也是我最终推荐 VsCode 的理由之一——编译器的版本高,表达能力完全不一样。
我个人在实际操作中的体会是:配置环境最花时间的其实不是 IDE 本身,而是"弄清楚自己下载的库是哪一位数、哪一个版本、README 里写了什么"。ege19.01 压缩包内的 README.txt 基本涵盖了各 IDE 的配置参数,先读它,再动手,至少能少走一半弯路。把这条路走通之后,你会发现 DEV-C++ 和 VsCode 之间的切换并不难,核心就一句话:头文件路径、库文件路径、链接参数,三样对齐,环境就稳了。