Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write a C wrapper around C++ classes with C++ callbacks

I need to wrap a C++ library with C. This C++ library defines callback functions. For example:

    // from C++ library

    typedef X CallbackFn(Y y); // X and Y are classes

    class Z
    {
    public:
            void addCallback( CallbackFn* fn ) { callbackFn = fn; }
    private:
            CallbackFn* callbackFn;
    };

In the C wrapper I could define new C callbacks, which call the C++ callbacks. Something like this:

    // in C wrapper

    extern "C" {

    typedef int CallbackFnC(int n, ... );

    CallbackFnC *callbackFnC;

    int addCallback(void* handle, CallbackFnC* fn) // handle is pointer to Z instance
    {
        callbackFnC = fn;
        ((Z*)handle)->addCallback(callbackFnCPP);
    }

    }

    X callbackFnCPP(Y y)
    {
        int rtn = callbackFnC(y.n, ...);
        return X(rtn);
    }

where I assume I can map the relevant members of Y to the arguments of the C callback function and that I can sufficiently construct the return type X from the C return.

Is this going to work? There's no way around defining the new C callbacks?

The new C callback should be inside the extern "C" and the defined instance of the C++ callback should be outside?

like image 428
jensph Avatar asked Dec 18 '12 13:12

jensph


1 Answers

Yes, replacing the C++ callback with a C callback and a C++ wrapper function will work (with some caveats) and no, if the C++ callback insists on passing/returning classes or references (as opposed to primitive types supported also by C), then the wrapper method is the only possible solution.

The main caveat of using a wrapper function is that the wrapper function needs some way to find the correct C function to call. Using a global is an easy solution, but now you are limited to one callback for the entire program (regardless of the number of Z objects you have). More flexible solutions will depend on the design of the C++ callback and will range from easy (on registration, you can provide arbitrary user-data that will be provided to the callback) to very hard.

like image 61
Bart van Ingen Schenau Avatar answered Nov 15 '22 06:11

Bart van Ingen Schenau