我知道这一点。
从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
答案 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(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 ++的规则编译此类。这段代码&#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(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。注意
答案 2 :(得分:5)
假设C ++ API是C兼容的(没有类,模板等),你可以将它包装在extern "C" { ... }
中,就像你从另一个方向那样。
如果你想公开对象和其他可爱的C ++东西,你必须编写一个包装器API。
答案 3 :(得分:5)
如果你想这样做,你必须在C ++中为C编写一个包装器。 C ++向后兼容,但C不向前兼容。
答案 4 :(得分:2)
将您的C ++函数导出为extern“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获得很多示例并不难。