如何从 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.

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

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

但是这里我要扩展一个用 C 编写的大型应用程序,我需要使用一个用 C + + 编写的库。C + + 的名称错误在这里造成了麻烦。连接器正在抱怨未解决的符号。我不能在我的 C 项目中使用 C + + 编译器,因为它破坏了很多其他的东西。出去的路是什么?

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

134058 次浏览

export your C++ functions as extern "C" (aka C style symbols), or use the .def file format to define undecorated export symbols for the C++ linker when it creates the C++ library, then the C linker should have no troubles reading it

You need to create a C API for exposing the functionality of your C++ code. Basically, you will need to write C++ code that is declared extern "C" and that has a pure C API (not using classes, for example) that wraps the C++ library. Then you use the pure C wrapper library that you've created.

Your C API can optionally follow an object-oriented style, even though C is not object-oriented. Ex:

// *.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);
}

Assuming the C++ API is C-compatible (no classes, templates, etc.), you can wrap it in extern "C" { ... }, just as you did when going the other way.

If you want to expose objects and other cute C++ stuff, you'll have to write a wrapper API.

You will have to write a wrapper for C in C++ if you want to do this. C++ is backwards compatible, but C is not forwards compatible.

I would do it in the following way:

(If working with MSVC, ignore the GCC compilation commands)

Suppose that I have a C++ class named AAA, defined in files aaa.h, aaa.cpp, and that the class AAA has a method named sayHi(const char *name), that I want to enable for C code.

The C++ code of class AAA - Pure C++, I don't modify it:

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

Compiling this class as regularly done for C++. This code "does not know" that it is going to be used by C code. Using the command:

g++ -fpic -shared aaa.cpp -o libaaa.so

Now, also in C++, creating a C connector:

Defining it in files aaa_c_connector.h, aaa_c_connector.cpp. This connector is going to define a C function, named AAA_sayHi(cosnt char *name), that will use an instance of AAA and will call its method:

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

Compiling it, again, using a regular C++ compilation command:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so

Now I have a shared library (libaaa_c_connector.so), that implements the C function AAA_sayHi(const char *name). I can now create a C main file and compile it all together:

main.c

#include "aaa_c_connector.h"


int main() {
AAA_sayHi("David");
AAA_sayHi("James");


return 0;
}

Compiling it using a C compilation command:

gcc main.c -L. -laaa_c_connector -o c_aaa

I will need to set LD_LIBRARY_PATH to contain $PWD, and if I run the executable ./c_aaa, I will get the output I expect:

Hi David
Hi James

EDIT:

On some linux distributions, -laaa and -lstdc++ may also be required for the last compilation command. Thanks to @AlaaM. for the attention

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

You can prefix the function declaration with extern “C” keyword, e.g.

extern “C” int Mycppfunction()

{

// Code goes here

return 0;

}

For more examples you can search more on Google about “extern” keyword. You need to do few more things, but it's not difficult you'll get lots of examples from Google.