簡體   English   中英

如何從 C 調用 C++ 函數?

[英]How to call C++ function from 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名稱C_library_function並且鏈接器會在其輸入 *.lib 文件中找到相同的名稱,問題就解決了。

從 C 調用 C++ 函數???

但是在這里我要擴展一個用 C 編寫的大型應用程序,我需要使用一個用 C++ 編寫的庫。 C++ 的名稱修改在這里造成了麻煩。 鏈接器抱怨未解析的符號。 好吧,我不能在我的 C 項目上使用 C++ 編譯器,因為那會破壞很多其他東西。 出路是什么?

順便說一下,我正在使用 MSVC

您需要創建一個 C API 來公開您的 C++ 代碼的功能。 基本上,您將需要編寫聲明為 extern "C" 並且具有包裝 C++ 庫的純 C API(例如,不使用類)的 C++ 代碼。 然后使用您創建的純 C 包裝庫。

您的 C API 可以選擇遵循面向對象的風格,即使 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 編譯命令)

假設我有一個名為AAA的 C++ 類,在文件aaa.h、aaa.cpp 中定義,並且類AAA有一個名為sayHi(const char *name) 的方法,我想為 C 代碼啟用該方法。

AAA類的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 中定義它。 此連接器將定義一個名為AAA_sayHi(cosnt char *name)的 C 函數,該函數將使用AAA的實例並調用其方法:

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 implement functions in C++, which will externally 
//   appear as C functions (which means that the function IDs will be their names, unlike
//   the regular C++ behavior, which allows defining multiple functions with the same name
//   (overloading) and hence uses function signature hashing to enforce unique IDs),


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

編輯:

在某些 linux 發行版上,最后一個編譯命令可能還需要-laaa-lstdc++ 感謝@AlaaM。 為了引起注意

如果你想這樣做,你將不得不用 C++ 為 C 編寫一個包裝器。 C++ 向后兼容,但 C 不向前兼容。

假設 C++ API 與 C 兼容(沒有類、模板等),您可以將其包裝在extern "C" { ... } ,就像您在其他方式時所做的那樣。

如果你想公開對象和其他可愛的 C++ 東西,你必須編寫一個包裝器 API。

將您的 C++ 函數導出為 extern "C"(又名 C 樣式符號),或者在創建 C++ 庫時使用 .def 文件格式為 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;
}

您可以使用 extern “C” 關鍵字作為函數聲明的前綴,例如

extern “C” int Mycppfunction()

{

// 代碼在這里

返回0;

}

有關更多示例,您可以在 Google 上搜索更多有關“extern”關鍵字的信息。 您需要做更多的事情,但不難從 Google 獲得大量示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM