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

VS编译的DLL在GCC程序中调用异常:执行错误函数

问题分析

你的问题核心是不同编译器(VS vs MinGW-posix)生成的虚函数表(vtable)布局不一致,同时x64调用约定存在差异,导致虚函数调用时索引错位:

  • VS的x64虚表第一个条目是RTTI信息指针,后续才是按声明顺序排列的虚函数地址;
  • MinGW-posix的x64虚表第一个条目就是第一个虚函数的地址,RTTI信息在虚表的前置位置;
  • 这直接导致GCC代码调用第一个虚函数时,实际访问的是VS虚表中的第二个条目(即下一个函数),完全匹配你描述的症状。
  • 另外你使用的MinGW-posix版本采用sysv调用约定,和VS的x64默认调用约定(Windows fastcall)不匹配,若函数有参数还会引发参数传递错误。
解决办法

方案1:改用C风格导出接口(最稳定,无编译器依赖)

放弃跨编译器的虚函数调用,将所有需要对外暴露的功能包装为extern "C"导出的C风格函数,完全避开虚表差异:

  1. 在Engine.hpp中添加C风格导出声明:
#ifdef ENGINE_EXPORTS
#define ENGINE_API __declspec(dllexport)
#else
#define ENGINE_API __declspec(dllimport)
#endif

// 前置声明类
class EngineDLL;

extern "C" {
    // 原有的实例创建/销毁函数
    ENGINE_API EngineDLL* __cdecl CreateModule();
    ENGINE_API void __cdecl DestroyModule(EngineDLL* instance);

    // 包装所有需要调用的虚函数
    ENGINE_API int __cdecl EngineServerClientHandshake(EngineDLL* instance, /* 原函数参数 */);
    ENGINE_API int __cdecl EngineGetHealthInfo(EngineDLL* instance, /* 原函数参数 */);
    ENGINE_API int __cdecl EngineGetLastError(EngineDLL* instance);
}
  1. 在DLL的实现文件中添加包装函数:
#include "Engine.hpp"
#include "EngineImp.hpp"

int EngineServerClientHandshake(EngineDLL* instance, /* 参数 */) {
    return instance->EngineServerClientHandshake(/* 参数 */);
}

int EngineGetHealthInfo(EngineDLL* instance, /* 参数 */) {
    return instance->EngineGetHealthInfo(/* 参数 */);
}

int EngineGetLastError(EngineDLL* instance) {
    return instance->EngineGetLastError();
}
  1. 调用程序直接通过这些C风格函数访问功能,不再通过类指针调用虚函数。

方案2:更换MinGW-W64为win32线程模型版本

将你使用的x86_64-posix-seh-rev0版本替换为x86_64-win32-seh-rev0版本:

  • 该版本的MinGW-W64采用和VS一致的Windows x64调用约定,同时虚表布局也和VS兼容(第一个条目为RTTI指针);
  • 更换后无需修改代码,原有的虚函数调用即可正常工作。

方案3:统一虚函数表布局(不推荐,依赖编译器实现细节)

如果你坚持使用虚函数调用,可以尝试在基类EngineDLL的最前面添加一个占位虚函数(无实际功能),抵消RTTI指针的索引差异:

class EngineDLL {
public:
    // 占位虚函数,仅用于抵消VS虚表的RTTI指针
    virtual void Placeholder() {}

    // 原有虚函数
    virtual int EngineServerClientHandshake(/* 参数 */) = 0;
    virtual int EngineGetHealthInfo(/* 参数 */) = 0;
    virtual int EngineGetLastError() = 0;

    // 确保虚析构,避免内存泄漏
    virtual ~EngineDLL() = default;
};

但该方案依赖编译器的具体实现,后续版本更新可能失效,仅作为临时 workaround。

内容的提问来源于stack exchange,提问作者C. O.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:50:03