How to pass a pointer to a member function to a C

2020-02-26 12:25发布

Possible Duplicate:
Using a C++ class member function as a C callback function

I'm writing an object-oriented library using a C library (winpcap). I need to pass the callback function that is called when a network packet arrives as a function pointer. I would like to pass a member function pointer to winpcap, to keep my design object oriented and to allow for different objects to receive different packets. However member functions as far as I understand have a different calling convention, and thus cannot be passed to a C function. Is there a way to fix this. My experiments with boost::bind (which I hardly manage to use other than trial and error) are not fruitful.

Is there a way to change the calling convention of a member function?

This is the definition of the callback function I use now and the actual passing of it to winpcap

void pcapCallback( byte* param, const struct pcap_pkthdr* header, const byte* pkt_data );

pcap_loop( adhandle, 0, pcapCallback, NULL );

The pcap_loop just takes the name of the function (which is on the global scope at the moment). This is the definition of the function pointer parameter (3rd parameter of pcap_loop). Since this is third party code I can't really change this. I would have to have a member function that can take this form:

typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);

As far as I understand it, the member function will be using thiscall and the c function pointer wants a cdecl

3条回答
干净又极端
2楼-- · 2020-02-26 12:35

Kindly refer to detailed topic about

How to Implement a Callback to a static C++ Member Function ?

How to Implement a Callback to a non-static C++ Member Function ?

http://www.newty.de/fpt/callback.html

查看更多
老娘就宠你
3楼-- · 2020-02-26 12:38

If you want to have a C API call a member function, you have to pass two pieces of data: the (static member) function and the object for which it is to be invoked.

Usually, C API callbacks have some form of "user data", often a void*, through which you can tunnel your object's address:

// Beware, brain-compiled code ahead!

typedef void (*callback)(int data, void* user_data);

void f(callback cb, void* user_data);

class cpp_callback {
public:
  virtual ~cpp_callback() {} // sometimes needed
  void cb(int data) = 0;
  callback* get_callback() const {return &cb_;}
private
  static void cb_(int data, void* user_data)
  {
    cpp_callback* that = reinterpret_cast<my_cpp_callback*>(user_Data);
    that->cb(data);
  }
};

class my_callback {
public:
  void cb(int data) 
  {
     // deal with data
  }
};

void g()
{
  my_callback cb;
  f(cb.get_callback(), &cb);
}

That pcapCallback doesn't look as if it has user data, though, unless that's what param is. If that's indeed the case, you'll have to store the callback object's address in some global variable before calling the API. Something like this:

// Beware, brain-compiled code ahead!

typedef void (*callback)(int data);

void f(callback cb);

class cpp_callback {
public:
  cpp_callback() : the_old_cb_(this) {std::swap(the_cb_,the_old_cb_);}
  virtual ~cpp_callback()            {std::swap(the_cb_,the_old_cb_);}
  void cb(int data) = 0;
  callback* get_callback() const {return &cb_;}
private
  static cpp_callback* the_cb_;
  cpp_callback* the_old_cb_;
  static void cb_(int data, void* user_data) 
  {
    the_cb_->cb(data);
  }
};

class my_callback {
public:
  void cb(int data) { /* deal with data */ }
};

void g()
{
  my_callback cb;
  f(cb.get_callback(), &cb);
}

As always with global data, this is perilous if more than one instance of the callback is alive. I have tried to minimize the harm so that it works if their lifetimes are nested. Anything else, though, will hurt.

查看更多
做自己的国王
4楼-- · 2020-02-26 12:47

You can only pass static member functions to a C API.

查看更多
登录 后发表回答