89

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

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
claws
  • 47,010
  • 55
  • 140
  • 185

7 Answers7

104

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);
 }
Michael Aaron Safyan
  • 87,518
  • 14
  • 130
  • 194
  • thanks!! got it. http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – claws Apr 30 '10 at 11:49
  • 1
    How do you link the final executable? Do you use C or C++? (When I used C, the linker couldn't find the C++ function; when I used C++, the linker couldn't find std::cout.) – Zack May 03 '16 at 14:48
  • 1
    @Zack if you create a static library with the C++ compiler/linker that transitively includes its dependencies (including the C++ standard library, which may be implicitly linked by your linker), you should be able to link that static library against C code using a C compiler/linker. – Michael Aaron Safyan May 04 '16 at 02:25
  • Can you export a template from C++ to C? – MarcusJ Mar 29 '18 at 13:04
  • I have an "hybrid" behavior as I need my library to be called both by C++ and C code. In the `*.cpp file` I also needed to wrap the functions into `#ifdef _cplusplus` + `extern "C"` to avoid "undefined reference to" errors at link time. – n0p Mar 29 '19 at 10:42
47

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

SomethingSomething
  • 9,410
  • 12
  • 56
  • 105
  • 1
    you could also specify the lib link path with `gcc usecpp.c -L. -laaa_c_connector -Wl,-rpath,. -o c_aaa` – Metaphox Oct 04 '16 at 10:49
  • what's `usecpp.c`? – Alaa M. Oct 30 '16 at 09:58
  • 1
    The last compilation line should be: `gcc main.c -L. -laaa_c_connector -laaa -lstdc++ -o c_aaa`. Note the `-laaa` and `-lstdc+++` – Alaa M. Oct 30 '16 at 12:23
  • @AlaaM. someone edited my code and changed `main.c` to `usecpp.c`. I've just reverted it.... About the other comment, it should work also as is. The second compilation uses `-laaa` and it should probably be enough (I wrote it more than 1.5 years ago, I don't remember very well what I did, but I think I tested every line before posting) – SomethingSomething Oct 30 '16 at 13:31
  • @SomethingSomething Oh OK I understand. And I tested it with Linaro [arm-linux-gnueabihf-gcc](https://launchpad.net/linaro-toolchain-binaries) and the 2 linking libs `-laaa` and `-lstdc++` were necessary for it to work. Otherwise I get some linking errors... – Alaa M. Oct 30 '16 at 13:35
  • 1
    Ok, added it as a note in the end of the post. Thanks for the attention! – SomethingSomething Oct 30 '16 at 13:55
6

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.

Puppy
  • 138,897
  • 33
  • 232
  • 446
5

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.

Marcelo Cantos
  • 167,268
  • 37
  • 309
  • 353
2

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

Necrolis
  • 24,554
  • 3
  • 57
  • 98
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;
}
-2

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.