Elegantly call C ++ from C

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

The ratio between the sizes of C and C++ is 20:1 , so switching to C++ not an option. Should we use a static library? Dll? (All this on Windows).

+42
c ++ c compilation shared-libraries
Sep 02 '11 at 9:17
source share
4 answers

EDIT: Based on the discussion in the comment, I should point out that splitting things up into a C-compatible struct duck and a derived class Duck is probably not necessary. You can probably safely translate the implementation into struct duck and eliminate class Duck , thereby getting rid of real(…) . But I do not know C ++ well enough (in particular, how it interacts with the C universe) to give a definitive answer to this.




There is no reason why you cannot simply link all your C and C ++ codes together into a single binary file.

Interacting with C ++ code requires you to wrap the C ++ API in API C. You can do this by declaring a bunch of functions inside extern "C" { ... } when compiling C ++ code and without extern declaration when compiling the code C. customer. For example :.

 #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 structure of a duck in a 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); } 
+50
02 Sep 2018-11-11T00:
source share

The only reason you need to inherit from duck struct is to show some attributes in the C API, which are considered bad 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 will be the appropriate implementation, without the need for type casting:

 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, the C API can be created for the C ++ interface (pure virtual class) and its implementation. In this case, only the constructor should be based on a specific implementation (for example, new_RubberDuck (2)). The destructor and all other functions will automatically work with the correct implementation, as in C ++.

+6
Jun 06 '13 at 13:29
source share

The C ++ math library can very well be implemented in utility classes (for static members only). In this case, a much simpler approach could be made:

 class FPMath { public: static double add(double, double); static double sub(double, double); static double mul(double, double); static double div(double, double); }; 

The header for the C interface will be as follows:

 double FPMath_add(double, double); double FPMath_sub(double, double); double FPMath_mul(double, double); double FPMath_div(double, double); 

And the corresponding implementation could be:

 double FPMath_add(double a, double b) { return FPMath::add(a, b); } double FPMath_sub(double a, double b) { return FPMath::sub(a, b); } double FPMath_mul(double a, double b) { return FPMath::mul(a, b); } double FPMath_div(double a, double b) { return FPMath::div(a, b); } 

But perhaps this speaks explicitly ....

+5
Jun 06 '13 at 13:55 on
source share

There is a way to create a β€œhack” that allows you to directly call member functions of some objects.

The first thing you need to do is create an extern "C" factory function that returns a pointer (like void* ) to the object.

The second thing you need is the garbled name of the member function.

You can then call the function using the search name and pass the pointer returned from the factory function as the first argument.

Cautions:

  • Of course, a call member function that wants other objects or links or other C ++ objects, or functions that return objects or types that are not compatible with C types, will not work.
  • It will not work with virtual member functions, and possibly not on objects with virtual functions in them, even if it is not a virtual function called
  • The broken name must be a valid C character
  • Any many others ...

This is not what I recommend, quite the opposite. I highly recommend not doing something like the one outlined in this answer. This unsupported and possibly undefined behavior can be violated in strange and unpredictable ways.

0
Sep 09 '15 at 11:48
source share



All Articles