2010-04-30 137 views
48

我知道这一点。如何从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. 

此止跌调用函数” t破解名称C_library_function和链接器将在其输入* .lib文件中找到相同的名称,并解决问题。

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

但是我在这里延伸的用C语言编写的大型应用程序,我需要使用的是用C++库。 C++的名称改变在这里引起麻烦。连接器抱怨未解决的符号。那么我不能在我的C项目上使用C++编译器,因为那会破坏很多其他的东西。什么是出路?

通过我使用的是MSVC

+4

阅读http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – jweyrich 2010-04-30 11:41:43

+0

当您控制C++库时:http:// stackoverflow。 com/questions/12615683/calling-c-functions-from-c-file – 2015-05-29 10:10:50

+2

可能出现[从C中优雅地调用C++]的副本(http://stackoverflow.com/questions/7281441/elegantly-call-c-from-c ) – user2284570 2017-03-13 22:48:26

回答

59

你需要创建一个C API来暴露你的C++代码的功能。基本上,您需要编写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); 
} 
+0

谢谢!!得到它了。 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – claws 2010-04-30 11:49:44

+1

感谢您的回答。但是,链接被破坏。 – Milo 2013-04-23 15:24:09

+1

谢谢。我没有意识到,当我删除它时,仍然存在来自StackOverlow的该页面的链接。我更新了答案,以提供更多详细信息,而无需引用该页面。 – 2013-05-09 09:52:36

2

出口你的C++函数为extern“C”(又名空调风格符号),或使用DEF文件格式来定义的C++连接器未修饰的出口符号的方式,当创建C++库,那么C连接不应该有麻烦阅读它

5

假设C++ API是C兼容(无类,模板等),你可以用它在extern "C" { ... },就像你走另一条路什么时候。

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

+0

不太... C++库需要重新编译。 – 2010-04-30 11:41:59

+0

哦,不, C++ API完全是面向对象的。 – claws 2010-04-30 11:42:15

+2

@claws,请参阅我的关于制作OOP风格的C代码的文章..并创建一个包含C接口但使用该风格的包装器库,但是是一个基础的C++实现。然后链接到C界面。 – 2010-04-30 11:43:36

5

你将不得不写了针对c包装在C++中,如果你想这样做。 C++向后兼容,但C不兼容。

17

我会做下列方式:

(如果有MSVC的工作,忽视了GCC编译命令)

假设我有一个名为AAA一个C++类,在文件中AAA中定义.h,aaa.cpp,并且类AAA有一个名为sayHi(常量字符*名称),我想启用C代码。

类的C++代码AAA - 纯C++,我不修改它:

// AAA。ħ

#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字符*姓名),将使用的实例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(为const char *名称)。我现在可以创建一个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。注意事项

+1

非常感谢。你的详细回答帮了我很多。 – Abhinav 2016-09-08 14:51:20

+1

你也可以用'gcc usecpp.c -L指定lib链接路径。 -laaa_c_connector -Wl,-rpath ,. -o c_aaa' – Metaphox 2016-10-04 10:49:17

+0

什么是'usecpp.c'? – 2016-10-30 09:58:09