I know this.
Calling C function from C++:
If my application was in C++ and I had to call functions from a library written in C. Then I would have used
//main.cpp extern "C" void C_library_function(int x, int y);//prototype C_library_function(2,4);// directly using it.
This wouldn't mangle the name C_library_function
and linker would find the same name in its input *.lib files and problem is solved.
Calling C++ function from C???
But here I'm extending a large application which is written in C and I need to use a library which is written in C++. Name mangling of C++ is causing trouble here. Linker is complaining about the unresolved symbols. Well I cannot use C++ compiler over my C project because thats breaking lot of other stuff. What is the way out?
By the way I'm using MSVC
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(untyped_ptr); delete typed_ptr; } void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) { MyType* typed_self = static_cast(untyped_self); typed_self->doIt(param); }
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 #include "aaa.h" AAA::AAA() { } void AAA::sayHi(const char *name) { std::cout
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 #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
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
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.
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