problem of call c++ functions from c that it used different decoration.
all next for cl.exe (msvc) + link.exe toolset, but think other compiler/linkers have analog features
for example when you compile in c++ function
void consoleDebug(char* format, ...)
in obj (or static lib) file will be ?consoleDebug@@YAXPEADZZ
symbol.
but when you use the same function from c unit - in object file will _consoleDebug
(for x86) or consoleDebug
(other platforms)
if we declare in c file
void consoleDebug(char* format, ...)
and do call - in obj will be stored that external symbol consoleDebug
(or _consoleDebug
) used. when linker will be build code - it will search - where is [_]consoleDebug
actually defined (in all obj and lib passed to him) and founf nothing - no such symbol. as result we got error unresolved external symbol [_]consoleDebug
solution here in undocumented linker option /alternatename
:
/alternatename:sym1=sym2
with this we say to linker (link.exe) if he need sym1
symbol and can not found it - try use sym2
instead. with this we can create next solution:
1 - we need know exactly symbol name in c++ - we can get it with __FUNCDNAME__
macro:
for example:
#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_
this is temporary, fake code, need only for print __FUNCDNAME__
then in c file we declare
void __cdecl consoleDebug(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebug=?consoleDebug@@YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebug=?consoleDebug@@YAXPEADZZ"))
#endif
and can free use consoleDebug
in case we have multiple functions in c++ with same short name, say
void consoleDebug(char* format, ...);
void consoleDebug(wchar_t* format, ...);
this is also easy work, need only bit different name this 2 api in c code:
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
after this we can simply call like
consoleDebugA("str %u\n", 1);
consoleDebugW(L"str %u\n", 2);
from c code.
no any shim/wrapper code need with this. in case you use not cl/link but other tool-chain and can not found analog of /alternatename
name option - possible use asm file for create single jmp
shim. say for 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