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

cla*_*aws 74 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.
Run Code Online (Sandbox Code Playgroud)

这不会破坏名称C_library_function,链接器会在其输入*.lib文件中找到相同的名称,问题就解决了.

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

但是在这里我扩展了一个用C语言编写的大型应用程序,我需要使用一个用C++编写的库.C++的名称错误导致了麻烦.Linker抱怨未解决的符号.好吧,我不能在我的C项目中使用C++编译器,因为这会破坏很多其他东西.出路是什么?

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

Mic*_*yan 85

您需要创建一个C API来公开C++代码的功能.基本上,您需要编写声明为extern"C"的C++代码,并且具有包装C++库的纯C API(例如,不使用类).然后使用您创建的纯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);
 }
Run Code Online (Sandbox Code Playgroud)

  • @Zack如果您使用 C++ 编译器/链接器创建一个静态库,该静态库可传递地包含其依赖项(包括 C++ 标准库,它可能由您的链接器隐式链接),那么您应该能够使用该静态库将该静态库链接到 C 代码C 编译器/链接器。 (2认同)

Som*_*ing 33

我会用以下方式做到这一点:

(如果使用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
Run Code Online (Sandbox Code Playgroud)

// aaa.cpp

#include <iostream>

#include "aaa.h"

AAA::AAA() {
}

void AAA::sayHi(const char *name) {
    std::cout << "Hi " << name << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

像C++一样定期编译这个类.此代码"不知道"它将被C代码使用.使用命令:

g++ -fpic -shared aaa.cpp -o libaaa.so
Run Code Online (Sandbox Code Playgroud)

现在,也是在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
Run Code Online (Sandbox Code Playgroud)

// 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
Run Code Online (Sandbox Code Playgroud)

再次使用常规C++编译命令对其进行编译:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so
Run Code Online (Sandbox Code Playgroud)

现在我有一个共享库(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;
}
Run Code Online (Sandbox Code Playgroud)

使用C编译命令编译它:

gcc main.c -L. -laaa_c_connector -o c_aaa
Run Code Online (Sandbox Code Playgroud)

我需要将LD_LIBRARY_PATH设置为包含$ PWD,如果我运行可执行文件./c_aaa,我将得到我期望的输出:

Hi David
Hi James
Run Code Online (Sandbox Code Playgroud)

编辑:

在某些Linux发行版上,aaa.haaa.cpp可能是最后一次编译命令所必需的.感谢@AlaaM.为了引起注意


Mar*_*tos 5

假设C++ API是C兼容的(没有类,模板等),你可以将它包装进去extern "C" { ... },就像你走另一条路一样.

如果你想暴露对象和其他可爱的C++东西,你将不得不编写一个包装器API.

  • @claws,请参阅我关于制作OOP样式C代码的文章..并使用带有C接口的样式创建一个包装器库,但是底层的C++实现.然后链接到C接口. (2认同)

Pup*_*ppy 5

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