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



Я знаю это.



вызов функции C из C++:



Если бы мое приложение было на C++ , и мне пришлось вызывать функции из библиотеки, написанной на C. Тогда я бы использовал



//main.cpp

extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.


это не испортит имя C_library_function и компоновщик найдет то же имя в своем входе *.lib файлы и проблема решена.



вызов функции C++ из C???



но здесь я расширяю большое приложение, которое является написан на C, и мне нужно использовать библиотеку, которая написана на C++. Имя искажение C++ вызывает проблемы здесь. Линкер жалуется на неразрешенные символы. Ну, я не могу использовать компилятор C++ над моим проектом C, потому что это нарушает много других вещей. Каков же выход?



кстати я использую MSVC

1798   6  

6 ответов:

вам нужно создать C API для предоставления функциональности вашего кода на C++. В принципе, вам нужно будет написать код C++, который объявлен extern "C" и который имеет чистый API C (не используя классы, например), который обертывает библиотеку C++. Затем вы используете чистую библиотеку оболочки C, которую вы создали.

ваш API C может дополнительно следовать объектно-ориентированному стилю, даже если C не является объектно-ориентированным. Например:

 // *.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);
 }

Я бы сделал это следующим образом:

(при работе с MSVC игнорируйте команды компиляции GCC)

предположим, что у меня есть класс C++ с именем ААА, определенными в файлах ААА.х, ААА.cpp, а то класс ААА есть метод с именем sayHi (const char * name), что я хочу включить для C-кода.

код класса C++ААА - чистый C++, я не изменяю это:

/ / aaa.h

#ifndef AAA_H
#define AAA_H

class AAA {
    public:
        AAA();
        void sayHi(const char *name);
};

#endif

/ / aaa.cpp

#include <iostream>

#include "aaa.h"

AAA::AAA() {
}

void AAA::sayHi(const char *name) {
    std::cout << "Hi " << name << std::endl;
}

компиляция этого класса, как обычно делается для C++. Этот код "не знает", что он будет использоваться код C. С помощью команды:

g++ -fpic -shared aaa.cpp -o libaaa.so

теперь, также В C++, создание соединителя C. Определение его в файлах aaa_c_connector.h, aaa_c_connector.cpp. Этот соединитель будет определять функцию C с именем AAA_sayHi (cosnt char *name), что будет использовать экземпляр ААА и вызовет свой метод:

/ / aaa_c_connector.h

#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

/ / aaa_c_connector.cpp

#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

компиляция его, опять же, с помощью обычной команды компиляции C++:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so

теперь у меня есть общая библиотека (libaaa_c_connector.so), что реализует функцию C AAA_sayHi (const char *name). Теперь я могу создать основной файл C и скомпилировать все вместе:

/ / main.c

#include "aaa_c_connector.h"

int main() {
    AAA_sayHi("David");
    AAA_sayHi("James");

    return 0;
}

компиляция с помощью команды компиляции C:

gcc main.c -L. -laaa_c_connector -o c_aaa

мне нужно будет установить LD_LIBRARY_PATH, чтобы содержать $PWD, и если я запускаю исполняемый файл ./c_aaa, я получу результат, который я ожидаю:

Hi David
Hi James

EDIT:

в некоторых дистрибутивах Linux -laaa и -lstdc++ также может потребоваться для последней команды компиляции. Спасибо @AlaaM. за внимание

предполагая, что API C++ совместим с C (без классов, шаблонов и т. д.), вы можете обернуть его в extern "C" { ... }, Так же, как вы делали, когда шли в другую сторону.

Если вы хотите выставить объекты и другие милые вещи C++, вам придется написать API-интерфейс оболочки.

вам придется написать обертку для C в C++ , если вы хотите это сделать. C++ является обратная совместимость, но не вперед совместимы.

экспортируйте свои функции C++ как extern " C " (aka C style symbols) или используйте .формат файла def для определения недекорированных символов экспорта для компоновщика C++ при создании библиотеки C++, тогда компоновщик C не должен иметь проблем с его чтением

#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;
}

Comments

    Ничего не найдено.