5

I've read the following article here that explain how to call c++ based functions from pure C code.

The method is best explained with the following example :

// C++ code:
class C {
    // ...
    virtual double f(int);
};
extern "C" double call_C_f(C* p, int i) // wrapper function
{
    return p->f(i);
}

/* C code: */
double call_C_f(struct C* p, int i);
void ccc(struct C* p, int i)
{
    double d = call_C_f(p,i);
    /* ... */
}

However, I fail to understand if where do i define an instance that is pointed by 'p'. notice that in the C code, it is delivered as pointer to opaque struct, and in the C++ code it's assumed to be pointer to valid instance of class C, but i didn't see where this pointer is being initialized.

p.s. Of course that each code block that relate to different language is compiled with an appropriate compiler, and different object file is created.

3 Answers 3

6

You need similar wrapper methods to create and destroy the C++ object.

C++ code:

extern "C" C * create_c()
{
    return new C;
}

extern "C" void destroy_c(C *p)
{
    delete p;
}

C code:

// forward declarations (better to put those in a header file)
struct C;
struct C * create_c();
double call_C_f(struct C* p, int i);
void destroy_c(struct C *p);

struct C * p = create_c();
double result = call_C_f(p, i);
destroy_c(p);
p = NULL;
Sign up to request clarification or add additional context in comments.

4 Comments

A nice add-on to this answer would be a paragraph about POD types since the fact that the C class has a virtual member function (preventing it from being a POD) is the real reason behind the need for an opaque struct.
thanks for the help. but in the Usage part, shouldn't i need to have function definition prior to calling. the definition is from type 'C * create_c()' ... but the C part doesn't recognize class C.
@Zohar81 just add struct C; to declare it
@Bryan - might want to emphasise the fact that the C code can see a declaration, but should not see a definition of struct C - only the C++ code should.
3

In the case of your example, p is an object of your class C. You would have to create it in C++ code, and than pass it to C.

You should also declare the pointers to your C++ class as void * in C. The type is unknown, and struct C implies it's a known struct, which is wrong.

Example:

extern "C" {
struct C;
struct C *create_c(void)
{
     return new C;
}

void destroy_c(struct C *ptr)
{
    delete ((C*)ptr);
}
}

11 Comments

@BryanChen It does work, that's not an issue. It just gives the wrong impression, that you actually know the type in the C code. Which you don't. It's an opaque type you don't know, hence the semantic is wrong, and void * has the correct semantic.
I find the use of a struct useful actually. As all void pointers are equal, while different struct pointers are not.
Opaque pointer means it is a pointer to some unknown type, which is a good use here. void * will just make the code unmaintainable/unreadable.
If only using void * and if you have several types wrapped, you won't get any warning if using the wrong type because all you have will be void *.
@jdarthenay You don't get a warning anyway, void * and struct C* are equal. C is not C++.
|
0

You'd create it in C++, most probably with new C(). There is no way of portably creating it in C, so in case the C code must be able to construct new instances, you'd have to write an extern "C" C* construct_C(); factory function for it; likewise for a destructor.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.