Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ idiom when using a C library which expects a function pointer? [duplicate]

Tags:

c++

I am using a C library in a C++ application. The C SDK has functions that take a callback function pointer as an argument. The signature of these functions is usually like:

typedef int (* Func) (type1 c, type2 d);

I have my code structured using classes in C++. However, I can't pass any member functions to this function as callback because it doesn't accept int (MyClass::*)(type1 c, type2 d) and only accepts int (*)(type1 c, type2 d).

I'm getting around this by defining all my callbacks as static in the various classes and then passing them to the C library which then works.

I am still new to C++ so I'm not sure if this is the right solution? The code works, but I'd love to hear if I'm doing this wrong.

like image 530
Plasty Grove Avatar asked Mar 05 '26 07:03

Plasty Grove


1 Answers

On most platforms your code is ever likely to encounter, your solution is fine. However, strictly speaking, there can be a platform where the C calling convention and C++ calling convention differ. On this platform, your code would not work.

The 100% correct solution (as opposed to the 99.9% correct one which you use) is to define a function with C language linkage as the callback. If you need this function to have member access to your class, it can then call a static member function in your class:

class MyClass
{
  static int secret;
public:
  static void callback() { secret = 42; }
};

extern "C" void callback() { MyClass::callback(); }

Note that it is considered good practice for authors of callback registration points (that is, authors of the library which will call you back) to provide a way for the user to associated void* data with the callback, which will be passed in as they call you. If your library allows that, you can use this void *user_data to pass in a pointer to your C++ class. With such a nicely-designed callback library, it could look like this:

class MyClass
{
  int secret;

public:
  void setSecret() { secret = 42; }
};

extern "C" void callback(void *userData) { static_cast<MyClass*>(userData)->setSecret(); }

MyClass mc;

int main()
{
  cLibrary_registerCallback(&callback, &mc);
}
like image 100
Angew is no longer proud of SO Avatar answered Mar 07 '26 22:03

Angew is no longer proud of SO



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!