简体   繁体   中英

How to call C++ function from C?

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

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

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.

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.

将您的 C++ 函数导出为 extern "C"(又名 C 样式符号),或者在创建 C++ 库时使用 .def 文件格式为 C++ 链接器定义未修饰的导出符号,那么 C 链接器应该可以轻松读取它

#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, eg

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM