How to use a C++ member function as the callback f

2019-01-23 15:01发布

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?

标签: c++ c callback
6条回答
劳资没心,怎么记你
2楼-- · 2019-01-23 15:23

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.

查看更多
放荡不羁爱自由
3楼-- · 2019-01-23 15:24

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.

查看更多
来,给爷笑一个
4楼-- · 2019-01-23 15:33

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.

查看更多
The star\"
5楼-- · 2019-01-23 15:33

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.

查看更多
仙女界的扛把子
6楼-- · 2019-01-23 15:38

This should work if your member function is static.

查看更多
一夜七次
7楼-- · 2019-01-23 15:40
  1. Make sure it's in global scope

  2. Use extern "C"

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

查看更多
登录 后发表回答