10

I have 2 projects decoder and dec in my visual studio. One has C code and other has C++ code using stl respectively.How do I instantiate the c++ classes in my c code inside decode project?

for e.g.
//instantiating object
reprVectorsTree *r1 = new reprVectorsTree(reprVectors1,8);
//using one of its function
r1->decode(code);

What do I need to do for this?

How do I access files from another project?

How do I make use of existing c++ code in C files?

--------edit---------- I have a class like this

class Node//possible point in our input space
{
public:
    std::vector<float> valuesInDim;//values in dimensions
    std::vector<bool> code;
    Node(std::vector<float>value);
    Node::Node(float x, float y);
Node::Node(std::vector<float> value,std::vector<bool> binary);


};

How do I use the above class in c++? If C only allows structs how do I map it to a struct?

  • Does your C code compile with the C++ compiler? If you can compile everything in C++ that would be the simplest solution. – Doug T. Aug 15 '12 at 14:24
  • 7
    So, you're asking how to use a code from a programming language in a different programming language? – Lanaru Aug 15 '12 at 14:25
  • 2
    You could create a sort of wrapper DLL in C++ using `extern "C"` for everything that just calls the class and wraps class instances in structs (I don't know if DLLs can do that, I'm a Linux guy who knows nothing about DLLs). – Linuxios Aug 15 '12 at 14:26
  • @Lanaru: Yes, but this is much more feasible than asking how to use a Lisp object in PHP or something like that. C and C++ are very similar, and most C and C++ compilers have them share (for the most part) an ABI. Getting C and C++ to interact is much easier than most other combinations. – Linuxios Aug 15 '12 at 14:27
  • 1
    possible duplicate of [calling c++ code from c](http://stackoverflow.com/questions/2399344/calling-c-code-from-c) –  Aug 15 '12 at 14:30
  • How about the opposite: Use the C code in a C++ program? – Sebastian Mach Aug 15 '12 at 14:30

4 Answers4

32

Give the C++ module a C interface:

magic.hpp:

struct Magic
{
    Magic(char const *, int);
    double work(int, int);
};

magic.cpp: (Implement Magic.)

magic_interface.h:

struct Magic;

#ifdef __cplusplus
extern "C" {
#endif

typedef Magic * MHandle;
MHandle create_magic(char const *, int);
void    free_magic(MHandle);
double  work_magic(MHandle, int, int);

#ifdef __cplusplus
}
#endif

magic_interface.cpp:

#include "magic_interface.h"
#include "magic.hpp"

extern "C"
{
    MHandle create_magic(char const * s, int n) { return new Magic(s, n); }
    void    free_magic(MHandle p) { delete p; }
    double  work_magic(MHandle p, int a, int b) { return p->work(a, b); }
}

Now a C program can #include "magic_interface.h" and use the code:

MHandle h = create_magic("Hello", 5);
double d = work_magic(h, 17, 29);
free_magic(h);

(You might even want to define MHandle as void * and add casts everywhere so as to avoid declaring struct Magic in the C header at all.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • it would make more sense to call `magic.cpp` `magic_interface.cpp` , and have the c++ implementation of magic in `magic.cpp` – Gir Aug 15 '12 at 14:33
  • 1
    The functions in magic.cpp should be surrounded by extern "C", otherwise you'll get link errors. Tested on MSVC2010. – Rango Aug 15 '12 at 14:47
  • 1
    @user494461: There's no difference in C++. Both `struct` and `class` designate class types (as I think would be obvious from my use of constructor and member function). – Kerrek SB Aug 15 '12 at 15:22
  • @KerrekSB what if one of the argument to a function is std::vector ? –  Aug 16 '12 at 06:36
  • @user494461: You could apply the above ideas recursively and make another opaque handler for `std::vector`, I suppose. – Kerrek SB Aug 16 '12 at 06:53
  • @Rango the link errors are also not going without extern "C"{ } enclosure of the implementation - I am getting an error for every function implemented –  Aug 16 '12 at 19:16
  • 1
    @user494461 Are you compiling the code with C? Be careful with the file type of the wrapper 'magic_interface.cpp'. It should be a .cpp, not a .c – Rango Aug 17 '12 at 11:47
  • Is it possible for `Magic` to be a `template class`? – 2i3r Nov 30 '20 at 19:09
  • 1
    @2i3r: Well, not in a way that you can expose to C, but ultimately that doesn't matter so much: you can instead make `MHandle` an alias for `void*` and then cast back and forth in your C++ code, to whatever C++ object type you like. – Kerrek SB Nov 30 '20 at 21:55
  • 1
    If you choose to declare `struct Magic` in the header, it appears the compiler needs `typedef struct Magic * MHandle;` in the typedef. – Kevin Jan 21 '21 at 16:18
5

In simple terms, you just do these:

  1. Write an interface function to convert all the class functions (constructor, destructor, member functions) as pure functions, and encapsulate them as extern "C"{ }
  2. Convert the pointer to the class as pointer to void, and carefully use type-cast wherever you define the "pure functions"
  3. Call the pure functions in the C-code.

For example here is my simple Rectangle class:

/*** Rectangle.h ***/
class Rectangle{
private:
    double length;
    double breadth;
public:
    Rectangle(double iLength, double iBreadth);
    ~Rectangle();
    double getLength();
    double getBreadth();
};

/*** Rectangle.cpp ***/
#include "Rectangle.h"
#include <iostream>
extern "C" {
    Rectangle::Rectangle(double l, double b) {
        this->length = l;
        this->breadth = b;
    }

    Rectangle::~Rectangle() {
        std::cout << "Deleting object of this class Rectangle" << std::endl;
    }

    double Rectangle::getLength() {
        return this->length;
    }

    double Rectangle::getBreadth() {
        return this->breadth;
    }
}

Now here is my interface to convert the class functions to pure functions. Notice how the pointer to the class is handled!

/*** RectangleInterface.h ***/
#ifdef __cplusplus
extern "C" {
#endif
    typedef void * RHandle;
    RHandle create_Rectangle(double l, double b);
    void    free_Rectangle(RHandle);
    double  getLength(RHandle);
    double  getBreadth(RHandle);

#ifdef __cplusplus
}
#endif

/*** RectangleInterface.cpp ***/ 
#include "RectangleInterface.h"
#include "Rectangle.h"
extern "C"
{
    RHandle create_Rectangle(double l, double b){
        return (Rectangle*) new Rectangle(l, b);
    };
    void free_Rectangle(RHandle p){
        delete (Rectangle*) p;
    }
    double getLength(RHandle p){
        return  ((Rectangle*) p)->getLength();
    }
    double getBreadth(RHandle p){
        return ((Rectangle*)p)->getBreadth();
    }
}

Now I can use these interface functions in my ".c" file as shown below. I just have to include the RectangleInterface.h function here, and the rest is taken care by its functions.

/*** Main function call ***/
#include <stdio.h>
#include "RectangleInterface.h"

int main()
{
    printf("Hello World!!\n");
    RHandle myRec = create_Rectangle(4, 3);
    printf("The length of the rectangle is %f\n", getLength(myRec));
    printf("The area of the rectangle is %f\n", (getLength(myRec)*getBreadth(myRec)));
    free_Rectangle(myRec);
    return 0;
}
Gowtham
  • 51
  • 1
  • 2
1

Make wrapper for instantiating C++ objects using C++ exported functions.And then call these functions from C code to generate objects.

Since one is function oriented and other is object oriented, you can use a few ideas in your wrapper:-

  1. In order to copy class member, pass an equivalent prespecified struct from C code to corresponding C++ function in order to fetch the data.
  2. Try using function pointers, as it will cut the cost, but be careful they can be exploited as well.

A few other ways.

perilbrain
  • 7,961
  • 2
  • 27
  • 35
0

you would need to write a wrapper in C.

something like this:

in class.h:

struct A{
   void f();
}

in class.cpp:

void A::f(){
}

the wrapper.cpp:

#include "wrapper.h"
void fWrapper(struct A *a){a->f();};
struct A *createA(){
   A *tmp=new A();
   return tmp;
}

void deleteA(struct A *a){
 delete a;
}

the wrapper.h for C:

struct A;
void fWrapper(struct A *a);
A *createA();

the C program:

#include "wrapper.h"
int main(){
    A *a;
    a=createA();
    fWrapper(a);
    deleteA(a);
}
Gir
  • 839
  • 5
  • 11
  • I have classes, not structs, can I simply replace it here? –  Aug 15 '12 at 14:42
  • i think C doesnt have a `class` keyword. (structs in c++ are similar to structs, but have different default access specifiers) – Gir Aug 15 '12 at 14:49
  • dont know. i never needed to use classes when i used the wrappers. you could probably get away with naming them classes in the c++ files and structs in the wrapper files. but this might lead to undefined behaviour – Gir Aug 15 '12 at 14:54