如何从C调用C ++函数?

时间:2010-04-30 11:36:36

标签: c++ c visual-c++ extern-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 ++的名称错误导致了麻烦。 Linker抱怨未解决的符号。好吧,我不能在我的C项目中使用C ++编译器,因为这会破坏很多其他东西。出路是什么?

顺便说一句,我正在使用MSVC

7 个答案:

答案 0 :(得分:75)

您需要创建一个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);
 }

答案 1 :(得分:27)

我会按以下方式进行:

(如果使用MSVC,请忽略GCC编译命令)

假设我有一个名为 AAA 的C ++类,在文件 aaa.h,aaa.cpp 中定义,并且该类 AAA 有一个名为 sayHi(con​​st 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 ++的规则编译此类。这段代码&#34;不知道&#34;它将被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 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(con​​st 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。注意

答案 2 :(得分:5)

假设C ++ API是C兼容的(没有类,模板等),你可以将它包装在extern "C" { ... }中,就像你从另一个方向那样。

如果你想公开对象和其他可爱的C ++东西,你必须编写一个包装器API。

答案 3 :(得分:5)

如果你想这样做,你必须在C ++中为C编写一个包装器。 C ++向后兼容,但C不向前兼容。

答案 4 :(得分:2)

将您的C ++函数导出为ex​​tern“C”(又名C样式符号),或者在创建C ++库时使用.def文件格式为C ++链接器定义未修饰的导出符号,然后C链接器应该没有麻烦读它

答案 5 :(得分:0)

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

答案 6 :(得分:-3)

您可以在函数声明的前面加上关键字“ C”,例如

外部“ C” int Mycppfunction()

{

//代码在这里

返回0;

}

有关更多示例,您可以在Google上搜索更多有关“ extern”关键字的信息。您还需要做更多的事情,但是从Google获得很多示例并不难。