程序一运行就崩溃怎么查 —— 从 Segfault 到崩溃日志
崩溃的三种常见类型
| 类型 | 表现 | 常见原因 |
|---|---|---|
| Segfault | 屏幕闪一下黑窗口然后消失 | 空指针解引用、数组越界、野指针 |
| abort() | 控制台显示 "terminate called after throwing..." | 异常没捕获、assert 失败、std::terminate |
| OOM (OutOfMemory) | 应用被系统直接杀掉 | 内存泄漏、创建了超大的 SDL 纹理 |
第一步:开启调试模式重跑
最简单也最有效的第一步——不要直接 Run,用 Debug 模式运行:
- 确认编译选项里开启了
-g(带调试符号)和-O0(关闭优化) - 在代码里不设断点,直接点 Debug
- 程序崩溃时,gdb 会在崩溃行自动停住
- 查看:当前停在哪一行、各变量的值、调用栈
如果 gdb 能在崩溃行停住,问题基本就定位了。
第二步:看崩溃日志
如果 Debug 模式也崩溃得太快、gdb 没抓到,看崩溃日志:
Android 的 logcat
在电脑上通过 adb logcat(需要 USB 调试开启)过滤:
adb logcat -s DEBUG *:S -c
adb logcat -s DEBUG
或者在手机上装一个「Logcat 查看器」类的 App,过滤 Cxxdroid 相关的崩溃信息。
典型的 Segfault 日志片段:
I/DEBUG ( 1234): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdeadbeef
I/DEBUG ( 1234): #00 pc 00001234 /data/data/ru.iiec.cxxdroid/files/build/mygame
I/DEBUG ( 1234): #01 pc 00001567 /data/data/ru.iiec.cxxdroid/files/build/mygame
Cxxdroid 的控制台输出
有些崩溃(特别是 abort 和 C++ 异常)Cxxdroid 的控制台会直接打印 backtrace:
terminate called after throwing an instance of 'std::runtime_error'
what(): something went wrong
Aborted
看到 what() 里的内容直接能定位问题。
第三步:检查最常见的崩溃原因
空指针解引用
Node *head = nullptr;
head->next = something; // Segfault!
调试器能直接抓到——停在这行时 head 显示为 0x0,一眼就能看到。
数组越界
int arr[3] = {1, 2, 3};
arr[100] = 42; // Segfault 或静默损坏
越界不一定立即崩溃——可能运行几分钟后才在完全不相关的地方 crash。这叫内存踩踏,最难调。用 AddressSanitizer(ASan)能直接检测。
在 CMake 里开启 ASan:
target_compile_options(myexe PRIVATE -fsanitize=address -g)
target_link_options(myexe PRIVATE -fsanitize=address)
ASan 运行时一旦检测到越界、use-after-free、double free 等问题,会精确报告:哪一行代码、什么类型的错误、附近的内存布局。比 gdb 强得多。
use-after-free
int *p = new int(5);
delete p;
std::cout << *p; // 读已释放内存 → 崩溃或脏数据
同样用 ASan 检测。
SDL 纹理 / 窗口创建失败没检查
SDL_Window *win = SDL_CreateWindow(...);
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, 0);
// 没检查 win 和 ren 是否为 null!
SDL_RenderClear(ren); // 如果 ren 是 null → Segfault
SDL 的任何创建函数都必须检查返回值:
SDL_Window *win = SDL_CreateWindow(...);
if (!win) {
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << "\n";
return 1;
}
Android 存储 / 权限问题
Cxxdroid 2026 版支持 SAF 之前的版本,如果项目放在外部存储但 Cxxdroid 没权限读取,打开文件会返回 null → 后续操作崩溃。
检查:项目目录放在 Cxxdroid 默认的内部存储里试试能不能正常跑。
终极手段:注释二分法
如果以上都试过了还定位不到:
- 把代码注释掉一半,跑剩下一半
- 如果不崩了,说明问题在被注释掉的那一半
- 把那一半再对半注释,继续缩小范围
- 直到定位到具体几行
虽然笨但绝对有效——再复杂的崩溃都能在 10 轮内定位。