как вызвать функцию c++ из c?

<p>я знаю это.</p><p><strong> вызов функции c из c++: </strong></p><p>если бы мое приложение было на c++, и мне нужно было вызывать функции из библиотеки, написанной на c. тогда я бы использовал </p><pre><code>//main.cpp extern "c" void c\_library\_function(int x, int y);//prototype c\_library\_function(2,4);// directly using it. </code></pre><p>это не исказит имя <code>c\_library\_function</code>, и компоновщик найдет то же имя во входных файлах * .lib, и проблема решена.</p><p><strong> вызов функции c++ из c ??? </strong></p><p>но здесь я расширяю большое приложение, написанное на c, и мне нужно использовать библиотеку, написанную на c++. искаженное имя в c++ вызывает здесь проблемы. линкер жалуется на неразрешенные символы. ну, я не могу использовать компилятор c++ над моим проектом c, потому что это ломает много других вещей. какой выход?</p><p>кстати я использую msvc</p>

<p>вам нужно создать c api для демонстрации функциональности вашего кода c++. по сути, вам нужно будет написать код c++, который объявлен extern «c» и имеет чистый api c (например, не использующий классы), который оборачивает библиотеку c++. затем вы используете созданную библиотеку чистой c-оболочки.</p><p>ваш c api может опционально следовать объектно-ориентированному стилю, хотя c не является объектно-ориентированным. пример:</p><pre><code> // *.h file // ... #ifdef \_\_cplusplus #define externc extern "c" #else #define externc #endif typedef void* mylibrary\_mytype\_t; externc mylibrary\_mytype\_t mylibrary\_mytype\_init(); externc void mylibrary\_mytype\_destroy(mylibrary\_mytype\_t mytype); externc void mylibrary\_mytype\_doit(mylibrary\_mytype\_t self, int param); #undef externc // ... // *.cpp file mylibrary\_mytype\_t mylibrary\_mytype\_init() { return new mytype; } void mylibrary\_mytype\_destroy(mylibrary\_mytype\_t untyped\_ptr) { mytype* typed\_ptr = static\_cast<mytype*>(untyped\_ptr); delete typed\_ptr; } void mylibrary\_mytype\_doit(mylibrary\_mytype\_t untyped\_self, int param) { mytype* typed\_self = static\_cast<mytype*>(untyped\_self); typed\_self->doit(param); } </code></pre>

<p>я бы сделал это следующим образом:</p><p>(при работе с msvc игнорируйте команды компиляции gcc)</p><p>предположим, что у меня есть класс c++ с именем<strong>aaa</strong>, определенный в файлах<strong> aaa.h, aaa.cpp </strong>, и что у класса<strong>aaa</strong>есть метод с именем<strong> sayhi ( const char * name) </strong>, который я хочу включить для кода c.</p><p>код c++ класса<strong>aaa</strong>- чистый c++, я не изменяю его:</p><p>// aaa.h</p><pre><code>#ifndef aaa\_h #define aaa\_h class aaa { public: aaa(); void sayhi(const char *name); }; #endif </code></pre><p>// aaa.cpp</p><pre><code>#include <iostream> #include "aaa.h" aaa::aaa() { } void aaa::sayhi(const char *name) { std::cout << "hi " << name << std::endl; } </code></pre><p>компиляция этого класса, как это обычно делается для c++. этот код «не знает», что он будет использоваться кодом си. используя команду:</p><pre><code>g++ -fpic -shared aaa.cpp -o libaaa.so </code></pre><hr><p>теперь, также в c++, создание c-коннектора. определив его в файлах<strong> aaa\_c\_connector.h, aaa\_c\_connector.cpp </strong>. этот соединитель будет определять функцию c с именем<strong> aaa\_sayhi (cosnt char * name) </strong>, которая будет использовать экземпляр<strong>aaa</strong>и будет вызывать ее метод:</p><p>// aaa\_c\_connector.h</p><pre><code>#ifndef aaa\_c\_connector\_h #define aaa\_c\_connector\_h #ifdef \_\_cplusplus extern "c" { #endif void aaa\_sayhi(const char *name); #ifdef \_\_cplusplus } #endif #endif </code></pre><p>// aaa\_c\_connector.cpp</p><pre><code>#include <cstdlib> #include "aaa\_c\_connector.h" #include "aaa.h" #ifdef \_\_cplusplus extern "c" { #endif // inside this "extern c" block, i can define c functions that are able to call c++ code static aaa *aaa\_instance = null; void lazyaaa() { if (aaa\_instance == null) { aaa\_instance = new aaa(); } } void aaa\_sayhi(const char *name) { lazyaaa(); aaa\_instance->sayhi(name); } #ifdef \_\_cplusplus } #endif </code></pre><p>снова скомпилируйте его, используя обычную команду c++:</p><pre><code>g++ -fpic -shared aaa\_c\_connector.cpp -l. -laaa -o libaaa\_c\_connector.so </code></pre><hr><p>теперь у меня есть общая библиотека (libaaa\_c\_connector.so), которая реализует функцию c<strong> aaa\_sayhi (const char * name) </strong>. теперь я могу создать главный файл c и собрать его все вместе:</p><p>// main.c</p><pre><code>#include "aaa\_c\_connector.h" int main() { aaa\_sayhi("david"); aaa\_sayhi("james"); return 0; } </code></pre><p>компиляция с помощью команды компиляции c:</p><pre><code>gcc main.c -l. -laaa\_c\_connector -o c\_aaa </code></pre><p>мне нужно будет установить ld\_library\_path, чтобы он содержал $ pwd, и если я запустите исполняемый файл<strong> ./c\_aaa </strong>, я получу ожидаемый вывод:</p><pre><code>hi david hi james </code></pre><p>правка:</p><p>в некоторых дистрибутивах linux для последней команды компиляции могут также потребоваться <code>-laaa</code> и <code>-lstdc++</code>. благодаря @alaam. за внимание</p>

<p>предполагая, что api c++ совместим с c (без классов, шаблонов и т.д.), вы можете обернуть его в <code>extern "c" { ... }</code>, как вы это делали, когда шли другим путем.</p><p>если вы хотите выставлять объекты и другие симпатичные c++ вещи, вам придется написать api-оболочку.</p>

<p>вам придется написать оболочку для c на c++, если вы хотите это сделать. c++ имеет обратную совместимость, но c не поддерживает прямую совместимость.</p>

<p>экспортируйте ваши функции c++ как extern "c" (или символы стиля c), или используйте формат файла .def, чтобы определить недекорированные символы экспорта для компоновщика c++, когда он создает библиотеку c++, тогда компоновщик c не должен иметь проблем с его чтением</p>

<pre><code>#include <iostream> ////////////// // c++ code // ////////////// struct a { int i; int j; a() {i=1; j=2; std::cout << "class a created\n";} void dump() {std::cout << "class a dumped: " << i << ":" << j << std::endl;} ~a() {std::cout << "class a destroyed\n";} }; extern "c" { // this is the c code interface to the class a static void *createa (void) { // create a handle to the a class return (void *)(new a); } static void dumpa (void *thisptr) { // call a->dump () if (thisptr != null) // i'm an anal retentive programmer { a *classptr = static\_cast<a *>(thisptr); classptr->dump (); } } static void *deletea (void *thisptr) { // destroy the a class if (thisptr != null) { delete (static\_cast<a *>(thisptr)); } } } //////////////////////////////////// // this can be compiled as c code // //////////////////////////////////// int main (int argc, char **argv) { void *handle = createa(); dumpa (handle); deletea (handle); return 0; } </code></pre>