Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegantly call C++ from C

We develop some project in plain C (C99). But, we have one library as source codes (math library) in C++. We need this library so I would like to ask, what is the most elegant way to integrate this source codes?

Ratio between sizes of C and C++ is 20:1 so moving to C++ is not the option. Should we use static library? DLL? (It's all on Windows).

like image 301
Cartesius00 Avatar asked Sep 02 '11 09:09

Cartesius00


People also ask

Can we call C++ library function directly from C library?

Accessing C++ Code from Within C SourceIf you declare a C++ function to have C linkage, it can be called from a function compiled by the C compiler. A function declared to have C linkage can use all the features of C++, but its parameters and return type must be accessible from C if you want to call it from C code.

What is extern C?

extern "C" is a linkage specification which is used to call C functions in the Cpp source files. We can call C functions, write Variables, & include headers. Function is declared in extern entity & it is defined outside.

Does C and C++ use the same compiler?

Code structure of both the languages are same. The compilation of both the languages is similar. They share the same basic syntax. Nearly all of C's operators and keywords are also present in C++ and do the same thing.


2 Answers

EDIT: Based on discussion in the comment, I should point out that separating things into a C-compatible struct duck and a derived class Duck is probably unnecessary. You can probably safely shovel the implementation into struct duck and eliminate class Duck, thus obviating real(…). But I don't know C++ well enough (in particular, the way it interacts with the C universe) to offer a definitive answer on this.


There is no reason you can't simply link all your C and C++ code together into a single binary.

Interfacing to the C++ code requires that you wrap the C++ API in a C API. You can do this by declaring a bunch of functions inside extern "C" { ... } when compiling the C++ code, and without the extern declaration when compiling the C client code. E.g.:

#ifdef __cplusplus extern "C" { #endif  typedef struct duck duck;  duck* new_duck(int feet); void delete_duck(duck* d); void duck_quack(duck* d, float volume);  #ifdef __cplusplus } #endif 

You can define the duck struct in your C++ source, and even inherit the real Duck class from it:

struct duck { };  class Duck : public duck { public:     Duck(int feet);     ~Duck();      void quack(float volume); };  inline Duck* real(duck* d) { return static_cast<Duck*>(d); }  duck* new_duck(int feet) { return new Duck(feet); } void delete_duck(duck* d) { delete real(d); } void duck_quack(duck* d, float volume) { real(d)->quack(volume); } 
like image 159
Marcelo Cantos Avatar answered Oct 10 '22 21:10

Marcelo Cantos


The only reason to want to inherit from the duck struct would be to expose some to its attributes in the C API, which is generally considered bad style anyway. Without inheritance, your C header would look like this:

struct Duck;  struct Duck* new_Duck(int feet); void delete_Duck(struct Duck* d); void Duck_quack(struct Duck* d, float volume); 

And this would be the corresponding implementation, with no need for type casts:

extern "C" { #include "Duck.h" }  class Duck { public:     Duck(int feet) : {}     ~Duck() {}      void quack(float volume) {} };  struct Duck* new_Duck(int feet) { return new Duck(feet); } void delete_Duck(struct Duck* d) { delete d; } void Duck_quack(struct Duck* d, float volume) { d->quack(volume); } 

In the same way, a C API can be created for a C++ interface (pure virtual class) and its implementations. In that case, only the constructor need to be based on the concrete implementation (e.g. new_RubberDuck(2)). The destructor and all other functions will automatically operate on the correct implementation, same as in C++.

like image 45
A.Robert Avatar answered Oct 10 '22 19:10

A.Robert