微软官方SEH示例代码MinGW-w64编译失败:原因及修改方案
MinGW-w64编译MSVC SEH示例代码出现链接错误
问题背景
从微软文档获取的SEH示例代码(原本适配MSVC编译器,需用cl /W4 /clr crt_set_se_translator_clr.cpp编译),在Windows 10 x64专业版的MSYS2环境下,使用MinGW-w64的g++(版本14.2.0)编译时,执行命令g++ gnu_better_seh.cc出现如下链接错误:
C:/winoss/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\VASILI~1\AppData\Local\Temp\ccprbtUh.o:gnu_better_seh:(.text$_ZN20Scoped_SE_TranslatorC1EPFvjP19_EXCEPTION_POINTERSE[_ZN20Scoped_SE_TranslatorC1EPFvjP19_EXCEPTION_POINTERSE]+0x1a): undefined reference to `__imp__Z18_set_se_translatorPFvjP19_EXCEPTION_POINTERSE' C:/winoss/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\VASILI~1\AppData\Local\Temp\ccprbtUh.o:gnu_better_seh:(.text$_ZN20Scoped_SE_TranslatorD1Ev[_ZN20Scoped_SE_TranslatorD1Ev]+0x19): undefined reference to `__imp__Z18_set_se_translatorPFvjP19_EXCEPTION_POINTERSE' collect2.exe: error: ld returned 1 exit status
原代码如下:
// crt_set_se_translator_clr.cpp // compile with: cl /W4 /clr crt_set_se_translator_clr.cpp #include <windows.h> #include <eh.h> #include <stdio.h> #include <exception> int thrower_func( int i ) { int y = 0; int *p = &y; *p = i / *p; return 0; } class SE_Exception : public std::exception { private: const unsigned int nSE; public: SE_Exception() noexcept : SE_Exception{ 0 } {} SE_Exception( unsigned int n ) noexcept : nSE{ n } {} unsigned int getSeNumber() const noexcept { return nSE; } }; class Scoped_SE_Translator { private: const _se_translator_function old_SE_translator; public: Scoped_SE_Translator( _se_translator_function new_SE_translator ) noexcept : old_SE_translator{ _set_se_translator( new_SE_translator ) } {} ~Scoped_SE_Translator() noexcept { _set_se_translator( old_SE_translator ); } }; #pragma unmanaged void my_trans_func( unsigned int u, PEXCEPTION_POINTERS ) { throw SE_Exception( u ); } void DoTest() { try { thrower_func( 10 ); } catch( const SE_Exception& e ) { printf( "Caught SE_Exception, error %8.8x\n", e.getSeNumber() ); } catch(...) { printf( "Caught unexpected SEH exception.\n" ); } } #pragma managed int main() { Scoped_SE_Translator scoped_se_translator{ my_trans_func }; DoTest(); }
原因分析
_set_se_translator是MSVC CRT独有函数:该函数是微软C运行时库(CRT)提供的扩展,用于将SEH(结构化异常处理)转换为C++异常,MinGW-w64的CRT并未实现此函数,因此链接时会出现未定义符号错误。- MSVC特有编译指令无效:原代码中的
#pragma managed和#pragma unmanaged是MSVC用于切换托管/非托管代码的指令,MinGW-w64不支持此类指令,需删除。
解决方法
方法1:修改代码适配MinGW-w64的SEH处理
替换_set_se_translator相关逻辑,改用MinGW支持的SEH捕获方式,直接使用__try/__except并手动转换SEH异常为C++异常。以下是修改后的代码:
#include <windows.h> #include <stdio.h> #include <exception> int thrower_func(int i) { int y = 0; int* p = &y; *p = i / *p; return 0; } class SE_Exception : public std::exception { private: const unsigned int nSE; public: SE_Exception() noexcept : SE_Exception{ 0 } {} SE_Exception(unsigned int n) noexcept : nSE{ n } {} unsigned int getSeNumber() const noexcept { return nSE; } }; // 自定义SEH异常过滤函数,将SEH异常转换为C++异常 LONG WINAPI seh_exception_filter(EXCEPTION_POINTERS* ep) { throw SE_Exception(ep->ExceptionRecord->ExceptionCode); return EXCEPTION_EXECUTE_HANDLER; } void DoTest() { __try { thrower_func(10); } __except (seh_exception_filter(GetExceptionInformation())) { // 异常已被转换并抛出,此处不会直接执行 } } int main() { try { DoTest(); } catch (const SE_Exception& e) { printf("Caught SE_Exception, error %8.8x\n", e.getSeNumber()); } catch (...) { printf("Caught unexpected SEH exception.\n"); } return 0; }
方法2:编译命令调整(配合代码修改)
编译修改后的代码时,需确保MinGW-w64启用SEH支持(x86_64架构下默认已支持),执行以下命令:
g++ -std=c++17 gnu_better_seh.cc -o gnu_better_seh.exe
注:-std=c++17可根据代码需求调整为对应C++标准版本
补充说明
MinGW-w64的SEH实现与MSVC存在差异:
- MinGW使用
__try/__except双下划线语法,与MSVC一致,但_set_se_translator这类转换函数是MSVC独有的,无法直接复用。 - 若需要贴近原代码的作用域式SEH转换,可以封装
__try/__except为RAII结构,但逻辑需重新实现。
内容的提问来源于stack exchange,提问作者Vasileios Anagnostopoulos
相关产品推荐
相关产品推荐

