简体   繁体   中英

How to use a C++ member function as the callback function for a C framework

There is a C library (which I cannot change) that supports a callback function of the type

void (*callback)(void *appContext, int eventid)

I want to set a C++ function as the callback.

Specifically I have following questions?

  1. Do I need to declare the callback function under "extern C" block?

  2. Does a member function need to be static to be the callback function? Is it possible to use a non-static member function? If yes, how? And when is it recommended to use a non-static member function?

  3. Does it matter if the function is a template function or not?

  4. Does a non-class C style function have any advantages over a class member function?

I am trying these variants on a old VC++ compiler, which does not support the latest C++ standard. But the code needs to be platform independent and should work on most C++ compilers. I want to know what is recommended practice with callbacks?

Does callback function need to be declared under extern "C"?

NO. extern "C" is necessary only when you are calling a C++ function directly, without the use of function pointers, from C. If function pointers are used, extern "C" is not required.

Can I use non-static member functions as a callback?

NO. Non-static member functions of class A have an implicit first parameter corresponding to this pointer.

Can I use static member functions as a callback?

YES, as long as signature matches with that of the callback.

Does it matter if the function is a template function or not?

NO, template function can be used as callbacks as long as the signature of the instantiated template matches with the callback.

This should work if your member function is static.

Assuming appContext is an opaque pointer that you pass to the function making the callback, you can get a callback to a member function of a specific object like this:

class myclass {

  void do_something() {
     // call function making the callback using _event_handler
     // as the callback function and the "this" pointer as appContext
  }

  // make sure the raw callback uses the correct calling convention (cdecl, stdcall, etc.)
  static void _handle_event(void* appContext, int eventid) {
    // forward the event to the actual object
    static_cast<myclass *>(appContext)->handle_event(eventid);
  }

  void handle_event(int eventid) {
     // do object-specific event handling
  }

};

Several answers mention extern "C" as a requirement. This is simply incorrect. extern "C" is necessary only when you are calling a C function directly from C++. It's used to tell the C++ compiler "do not apply name-mangling when generating the symbol name for this function". You are passing a C++ function pointer to a C function. As long as the calling conventions match, it will work just fine. The function's name is never involved.

It is not as simple as declaring the callback function under an extern "C" block. You need to figure out what calling convention the C library uses for its functions.

The terms I'm going to use are Microsoft specific, but the same rules should apply to other platforms too.

By default, the Visual C++ compiler makes C function __stdcall and C++ functions __cdecl .You cannot mix and match these calling conventions since each of these makes different assumptions about who cleans the stack. Here's a more detailed explanation.

Once you've matched the calling conventions, the easiest approach is to declare your C++ callback function as a namespace scope free standing function; or if it needs to be a member function, then a static member function. In both cases you should be able to bind a pointer to the instance of the class using std::bind . You might even be able to use std::bind to bind a non-static member function but I can't recall the syntax off the top of my head.

  1. Make sure it's in global scope

  2. Use extern "C"

  3. Use __cdecl , if needed: void (_cdecl *callback)

Strictly speaking, you cannot. A C callback must be designated extern "C" , which is not possible for member functions. Only freestanding functions can be used. You may forward calls from there to any C++ function, including static or non-static member functions.

Depending on the platform, you sometimes may be able to get away with skipping extern "C" , but I wouldn't test my luck.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM