C++如何捕获Access Violation异常并记录VS2019调试模式下的出错代码行
VS2019调试模式下捕获访问违例并记录代码行号的方案
访问违例属于Windows平台的结构化异常(SEH),不是C标准异常,默认配置下C的普通catch块无法捕获,可按以下步骤实现需求:
第一步:调整项目编译配置
- 右键项目 → 属性 → C/C++ → 代码生成 → 「启用C异常」选择
是,但有SEH异常 (/EHa),该选项是C语法捕获结构化异常的前提,默认的/EHsc配置仅能捕获C++标准异常 - 确认属性 → C/C++ → 常规 → 「调试信息格式」设置为
程序数据库(/Zi)或者用于编辑并继续的程序数据库(/ZI),保证pdb文件中包含代码行号映射信息
第二步:捕获异常并解析行号
可以直接使用Windows原生SEH机制配合DbgHelp库解析调用栈获取行号,示例代码如下:
#include <windows.h> #include <dbghelp.h> #include <iostream> #pragma comment(lib, "dbghelp.lib") // 异常过滤函数,解析异常上下文获取行号 LONG WINAPI AccessViolationFilter(_EXCEPTION_POINTERS* ExceptionInfo) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { std::cout << "捕获到访问违例异常" << std::endl; // 初始化符号解析器 SymInitialize(GetCurrentProcess(), NULL, TRUE); SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); // 64位编译取Rip寄存器,32位编译改为Eip void* exception_addr = (void*)ExceptionInfo->ContextRecord->Rip; IMAGEHLP_LINE64 line_info = {0}; line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD displacement = 0; if (SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)exception_addr, &displacement, &line_info)) { std::cout << "出错位置:" << line_info.FileName << " 第" << line_info.LineNumber << "行" << std::endl; } SymCleanup(GetCurrentProcess()); } return EXCEPTION_EXECUTE_HANDLER; } int main() { __try { // 你的业务代码放在此处,下方是触发访问违例的测试代码 int* p = nullptr; *p = 10; } __except (AccessViolationFilter(GetExceptionInformation())) { // 记录完成后直接退出,避免内存损坏导致更多问题 exit(1); } return 0; }
注意事项
- 调试运行时需要保证生成的pdb文件和exe在同一目录,否则无法解析行号
- 访问违例通常意味着进程内存已经出现不可控损坏,捕获记录后建议直接终止程序,不要继续执行业务逻辑
- 开启
/EHa选项后也可以用catch(...)捕获访问违例,但要获取异常上下文还是需要调用GetExceptionInformation,相比之下__try/__except的写法更直接
内容的提问来源于stack exchange,提问作者codefast
相关产品推荐
相关产品推荐

