проблема вызова c ++ функций из c в том, что он использовал разные декорации.
все следующее для cl.exe (msvc) + link.exe набора инструментов, но думаю, что другие компиляторы / компоновщики имеют аналоговые функции
, например, при компиляции в c ++ function
void consoleDebug(char* format, ...)
в obj (или статический lib ) файл будет иметь символ ?consoleDebug@@YAXPEADZZ
.но когда вы используете ту же функцию из c unit - в объектном файле будет _consoleDebug
(для x86 ) или consoleDebug
(для других платформ)
, если мыобъявить в c файл
void consoleDebug(char* format, ...)
и сделать вызов - в obj будет сохранен этот внешний символ consoleDebug
(или * 1041)*) используемый.когда компоновщик будет кодом сборки - он будет искать - где реально определено [_]consoleDebug
(всего передано ему obj и lib ) и нет ничего - такого символа нет.в результате мы получили ошибку неразрешенный внешний символ [_]consoleDebug
решение здесь в опции недокументированного компоновщика /alternatename
:
/alternatename:sym1=sym2
с этиммы говорим компоновщику ( link.exe ), если ему нужен символ sym1
и он не может его найти - попробуйте использовать 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, ...);
этоТакже легко работать, нужно только немного другое имя это 2 API в C код:
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
прокладки.скажем за 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