You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

微软官方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();
}

原因分析

  1. _set_se_translator是MSVC CRT独有函数:该函数是微软C运行时库(CRT)提供的扩展,用于将SEH(结构化异常处理)转换为C++异常,MinGW-w64的CRT并未实现此函数,因此链接时会出现未定义符号错误。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:05:08