从 c 调用 c++ 函数的问题是它使用了不同的装饰。
cl.exe (msvc) + link.exe 工具集的所有下一个,但认为其他编译器/链接器具有模拟功能
例如当你在c++函数中编译时
void consoleDebug(char* format, ...)
在 obj(或静态 lib)文件中将是 ?consoleDebug@@YAXPEADZZ 符号。
但是当您使用 c 单元中的相同功能时 - 在目标文件中将 _consoleDebug(对于 x86)或 consoleDebug(其他平台)
如果我们在 c 文件中声明
void consoleDebug(char* format, ...)
并调用 - obj 将存储使用的外部符号 consoleDebug(或 _consoleDebug)。当链接器将是构建代码时 - 它会搜索 - [_]consoleDebug 实际定义在哪里(在所有传递给他的 obj 和 lib 中)并且什么都没有 - 没有这样的符号。结果我们得到了错误unresolved external symbol [_]consoleDebug
在未记录的链接器选项中的解决方案 /alternatename :
/alternatename:sym1=sym2
如果他需要 sym1 符号但找不到它,我们会告诉链接器 (link.exe) - 尝试改用 sym2。有了这个,我们可以创建下一个解决方案:
1 - 我们需要准确地知道 c++ 中的符号名称 - 我们可以通过 __FUNCDNAME__ 宏获得它:
例如:
#define _GET_NAMES_
#ifdef _GET_NAMES_
void consoleDebug(char* format, ...)
{
#pragma message(__FUNCSIG__ ";\r\n")
#pragma message("__pragma(comment(linker, \"/alternatename:" __FUNCTION__ "=" __FUNCDNAME__ "\"))")
}
#endif // _GET_NAMES_
这是临时的假代码,只需要打印__FUNCDNAME__
然后在 c 文件中我们声明
void __cdecl consoleDebug(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebug=?consoleDebug@@YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebug=?consoleDebug@@YAXPEADZZ"))
#endif
并且可以免费使用consoleDebug
如果我们在 c++ 中有多个具有相同短名称的函数,比如说
void consoleDebug(char* format, ...);
void consoleDebug(wchar_t* format, ...);
这也很简单,只需要在c代码中为这2个api命名一点不同:
void __cdecl consoleDebugA(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugA=?consoleDebug@@YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugA=?consoleDebug@@YAXPEADZZ"))
#endif
void __cdecl consoleDebugW(wchar_t *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugW=?consoleDebug@@YAXPA_WZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugW=?consoleDebug@@YAXPEA_WZZ"))
#endif
在此之后我们可以简单地调用类似
consoleDebugA("str %u\n", 1);
consoleDebugW(L"str %u\n", 2);
来自 c 代码。
这个不需要任何垫片/包装器代码。如果您使用的不是 cl/link 而是其他工具链并且找不到 /alternatename 名称选项的模拟 - 可能使用 asm 文件来创建单个 jmp shim .说 x64
extern ?consoleDebug@@YAXPEADZZ:proc
extern ?consoleDebug@@YAXPEA_WZZ:proc
_TEXT segment 'CODE'
consoleDebugA proc
jmp ?consoleDebug@@YAXPEADZZ
consoleDebugA endp
consoleDebugW proc
jmp ?consoleDebug@@YAXPEA_WZZ
consoleDebugW endp
_TEXT ENDS
END