Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use shared library created in C++ in a C program?

I am creating programs using C. However, I require to use a lot of libraries that have API's only for C++. So, is it possible that I can create a shared object in C++ and then access its functionality using C?

  1. The only data I would be passing and returning would be C compatible data types.
  2. Converting or migrating to cpp is not an option here.

If it is not possible to interface these codes, how do I get information from C++ code to C code? I tried calling C++ functions from C, but I get errors during linking when I include <string>. So when I call C++ functions from C, should I only use that code which will be C compiler compatible?

C++ header cppfile.hpp

#ifndef CPPFILE_H #define CPPFILE_H     #ifdef __cplusplus     extern "C" {     #endif      extern int myfunction(const char *filename);     #ifdef __cplusplus    }    #endif #endif 

C++ file cppfile.cpp

#include "cppfile.hpp" #include <string> int myfunction(const char *filename) {     String S(filename);     return 0; } 

C file cmain.c

#include "cppfile.hpp" int main(int argc, char **argv) {      int i = myfunction(argv[1]);      printf("%d\n", i);      return 0; } 

Compiling:

gcc -c cmain.c g++ -fPIC -shared -o cppfile.so cppfile.cpp 
like image 597
coolharsh55 Avatar asked Feb 17 '13 04:02

coolharsh55


People also ask

Can I use CPP library in C?

If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible. Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.

What is a shared library in C?

Shared libraries (also called dynamic libraries) are linked into the program in two stages. First, during compile time, the linker verifies that all the symbols (again, functions, variables and the like) required by the program, are either linked into the program, or in one of its shared libraries.

How do shared libraries work?

Simply put, A shared library/ Dynamic Library is a library that is loaded dynamically at runtime for each application that requires it. Dynamic Linking doesn't require the code to be copied, it is done by just placing name of the library in the binary file.

How do I open a shared library file?

If you want to open a shared-library file, you would open it like any other binary file -- with a hex-editor (also called a binary-editor). There are several hex-editors in the standard repositories such as GHex (https://packages.ubuntu.com/xenial/ghex) or Bless (https://packages.ubuntu.com/xenial/bless).


2 Answers

You want something more like this (and here I will use a slightly more meaningful example):

C/C++ header - animal.h

#ifndef ANIMAL_H #define ANIMAL_H  #ifdef __cplusplus class Animal { public:     Animal() : age(0), height(0) {}     Animal(int age, float height) : age(age), height(height) {}     virtual ~Animal() {}      int   getAge();     void  setAge(int new_age);      float getHeight();     void  setHeight(float new_height);  private:     int age;     float height; // in metres! }; #endif /* __cplusplus */  #ifdef __cplusplus extern "C" { #endif     struct animal; // a nice opaque type      struct animal *animal_create();     struct animal *animal_create_init(int age, float height);     void           animal_destroy(struct animal *a);      void           animal_setage(struct animal *a, int new_age);     void           animal_setheight(struct animal *a, float new_height);     int            animal_getage(struct animal *a);     float          animal_getheight(struct animal *a); #ifdef __cplusplus } #endif  #endif /* ANIMAL_H */ 

C++ animal implementation file - animal.cpp

#include "animal.h" #define TO_CPP(a) (reinterpret_cast<Animal*>(a)) #define TO_C(a)   (reinterpret_cast<animal*>(a))  void  Animal::setAge(int new_age) { this->age = new_age; } int   Animal::getAge() { return this->age; } void  Animal::setHeight(float new_height) { this->height = new_height; } float Animal::getHeight() { return this->height; }  animal *animal_create() {     animal *a = TO_C(new Animal);     return a; }  animal *animal_create_init(int age, float height) {     animal *a = TO_C(new Animal(age, height));     return a; }  void animal_destroy(animal *a) {     delete TO_CPP(a); }  void animal_setage(animal *a, int new_age) {     TO_CPP(a)->setAge(new_age); }  void animal_setheight(animal *a, float new_height) {     TO_CPP(a)->setHeight(new_height); }  int animal_getage(animal *a) {     TO_CPP(a)->getAge(); }  float animal_getheight(animal *a) {     TO_CPP(a)->getHeight(); } 

C client code - main.c

#include "animal.h" #include <stdio.h>  int main() {     // 6'0" 25yo (perhaps a human? :P)     struct animal *a = animal_create(25, 1.83);       animal_setage(a, 26); // birthday     printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));      animal_destroy(a);     return 0; } 

C++ client code - main.cpp

#include "animal.h" #include <iostream>  int main() {     // 6'0" 25yo (perhaps a human? :P)     Animal* a = new Animal(25, 1.83);     a->setAge(26); // birthday     std::cout << "Age:    " << a->getAge() << std::endl;     std::cout << "Height: " << a->getHeight();      delete a;     return 0; } 

So when you compile the library, you compile animal.cpp with a C++ compiler. You can then link to it with C code, and use the animal_xxx functions.

Note the use of struct animal and Animal. Animal is a normal C++ type. It's exactly what it looks like. struct animal, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*.

In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle, you probably want at least jungle_setmalloc and jungle_setfree with sensible defaults. You can then set up the global new and delete in libjungle's C++ code to use these user-defined functions.

like image 169
Miles Rout Avatar answered Oct 11 '22 21:10

Miles Rout


This is entirely possible. Here is how, quickly: 1.) You have a header.h with a C API that doesn't include any Cplusiness.

#ifndef MIXEDCCPP_H #define MIXEDCCPP_H  #ifdef __cplusplus extern "C" { #endif #include <stdint.h> // Any C-compatible headers will go here.  // C API goes here.  C Functions can't contain any CPPiness. void myclass_setName( void *pClassObj, const char *pName, int nameLen );  #ifdef __cplusplus } #endif  #ifdef __cplusplus  // Stuff that is only compatible with CPP goes here // __cplusplus section won't get processed while compiling C files.  #include <vector> // CPP headers.   class MyClass {    // Classes etc. }; #endif // #ifdef __cplusplus  #endif // MIXEDCCPP_H 

Then in the .cpp, you simply create some C-API functions that can even include CPP right in them:

#include "mixedccpp.h"  extern "C" { // C API goes here.  C Functions can't contain any CPPiness in their prototypes. void myclass_setName( void *pClassObj, const char *pName, int nameLen ) {     // But CPP knowledge can go inside the function - no problem, since this is a CPP file.     MyClass *pMyClass = static_cast<MyClass *>(pClassObj);     pMyClass->setName( pName, nameLen ); }  } // #extern "C"   // CPP Stuff goes here... or vice-versa. 

In your case, you don't actually need any CPP code declared in your header since you are calling external libraries. But you need to create C-compatible functions in your CPP file which can call out to CPP libraries. Use extern "C" for those functions that need to be called from C files, and then use C-structs instead of classes and, if classes are needed, use void * to point to them and then cast them back to their class from the C function any time you need to access them. A standard makefile should be able to compile this just fine, assuming it compiles .cpp files as .cpp and understands extern "C" {}

like image 37
c.fogelklou Avatar answered Oct 11 '22 21:10

c.fogelklou