windows seh是操作系统级异常机制,可捕获访问违规、除零等硬件/系统异常;c++ try/catch仅处理throw抛出的语言级异常,二者默认不互通,seh异常无法被catch捕获。

什么是Windows SEH异常,和C++ try/catch有啥区别
Windows SEH(Structured Exception Handling)是操作系统级的异常机制,能捕获访问违规(ACCESS_VIOLATION)、除零、栈溢出等底层错误;而C++ try/catch只管C++异常(throw出来的对象),对SEH完全无感。两者默认不互通——你写了try { int* p = nullptr; *p = 1; } catch(...) {},照样崩,因为解引用空指针触发的是SEH,不是C++异常。
用SetUnhandledExceptionFilter注册全局SEH处理器
这是最直接、最低侵入的方式,适用于想在崩溃前做日志、dump或紧急保存的场景。注意:它只捕获当前线程未被其他SEH处理程序拦截的异常,且在DLL中注册需格外小心线程安全与卸载时机。
实操要点:
-
SetUnhandledExceptionFilter必须在主线程早期调用(比如main()开头),晚于CRT初始化可能失效 - 回调函数签名必须是
LPTOP_LEVEL_EXCEPTION_FILTER,返回值决定是否继续传递异常:EXCEPTION_EXECUTE_HANDLER表示已处理,进程将终止;EXCEPTION_CONTINUE_SEARCH让系统继续找别的处理器 - 不要在回调里调用CRT函数(如
printf、malloc),因堆/IO可能已损坏;推荐用WriteConsoleA或OutputDebugStringA - 64位下该API仍有效,但结构化异常链更严格,某些异常(如调试器接管时)可能绕过它
LONG WINAPI MyUnhandledHandler(EXCEPTION_POINTERS* pExp) {
// 安全写日志(不调malloc/printf)
OutputDebugStringA("SEH crash detected!\n");
// 可调用MiniDumpWriteDump生成dmp
return EXCEPTION_EXECUTE_HANDLER;
}
// 在main()开头:
SetUnhandledExceptionFilter(MyUnhandledHandler);
用__try/__except把SEH转成C++异常(慎用)
微软扩展语法__try/__except可直接捕获SEH,并在__except块中用throw抛出C++异常,实现“桥接”。但它不是标准C++,仅限MSVC,且不能嵌套在try块内(会编译报错C2712)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
关键限制:
-
__try块内不能有构造/析构语义的对象(比如局部std::string),否则编译失败——因为SEH展开不调用C++析构函数,编译器拒绝冒险 -
__except表达式里不能调用函数(除非是intrinsic如GetExceptionCode()),所以无法做复杂判断 - 仅对当前作用域生效,无法全局捕获;适合包裹已知高危代码段(如插件调用、外部DLL函数)
__try {
int* p = nullptr;
*p = 42; // 触发SEH
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
throw std::runtime_error("Access violation caught via SEH");
}
为什么MiniDumpWriteDump比自己解析CONTEXT更靠谱
有人想从EXCEPTION_POINTERS里手动读寄存器、栈帧、模块列表来还原现场,但Windows x64的栈展开规则(RBP链失效、基于UNWIND_INFO)极复杂,手写极易漏掉关键帧。而MiniDumpWriteDump由dbghelp.dll提供,已适配各Windows版本的内部结构,且支持多种dump类型(MiniDumpWithFullMemory、MiniDumpWithIndirectlyReferencedMemory等)。
使用前提:
- 链接
dbghelp.lib,运行时确保dbghelp.dll可用(WinXP SP2+自带) - 调用前最好用
SetErrorMode(SEM_NOGPFAULTERRORBOX)关掉系统弹窗,避免阻塞 - dump文件需配合PDB才能符号化;若发布Release版,务必保留对应PDB并记录build ID
- 不要在
SetUnhandledExceptionFilter回调里直接调用fopen写文件——磁盘IO可能卡死,建议用CreateFileA+FILE_FLAG_WRITE_THROUGH
真正难的不是抓异常,而是让dump能定位到源码行号、看清std::vector内容、还原线程间调用关系——这取决于PDB质量、编译选项(/Zi vs /Z7)、以及是否启用了增量链接(/INCREMENTAL)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










