6

可能重复:
使用 C++ 类成员函数作为 C 回调函数

我正在使用 C 库(winpcap)编写一个面向对象的库。我需要将网络数据包到达时调用的回调函数作为函数指针传递。我想将成员函数指针传递给 winpcap,以保持我的设计面向对象并允许不同的对象接收不同的数据包。然而,据我所知,成员函数具有不同的调用约定,因此不能传递给 C 函数。有没有办法解决这个问题。我对 boost::bind 的实验(除了反复试验,我几乎没有使用过)没有成果。

有没有办法改变成员函数的调用约定?

这是我现在使用的回调函数的定义以及将它实际传递给winpcap

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

pcap_loop( adhandle, 0, pcapCallback, NULL );

pcap_loop 只取函数的名称(目前在全局范围内)。这是函数指针参数(pcap_loop的第三个参数)的定义。由于这是第三方代码,我无法真正改变它。我必须有一个可以采用这种形式的成员函数:

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

据我了解,成员函数将使用 thiscall 并且 c 函数指针需要一个 cdecl

4

3 回答 3

5

请参阅有关的详细主题

如何实现对静态 C++ 成员函数的回调?

如何实现对非静态 C++ 成员函数的回调?

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

于 2010-06-24T09:42:04.153 回答
4

您只能将static成员函数传递给 C API。

于 2010-06-24T09:24:07.560 回答
4

如果要让 C API 调用成员函数,则必须传递两条数据:(静态成员)函数和要调用它的对象。

通常,C API 回调具有某种形式的“用户数据”,通常是 a void*,您可以通过它隧道访问对象的地址:

// 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);
}

但是,这pcapCallback看起来好像没有用户数据,除非那是真实param的。如果确实如此,则必须在调用 API 之前将回调对象的地址存储在某个全局变量中。像这样的东西:

// 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);
}

与全局数据一样,如果不止一个回调实例处于活动状态,这是很危险的。我试图将伤害降到最低,这样如果它们的生命周期是嵌套的,它就会起作用。但是,其他任何事情都会受到伤害。

于 2010-06-24T09:38:59.370 回答