如何将指向成员函数的指针传递给C函数?

时间:2010-06-24 09:22:18

标签: c++ c function-pointers winpcap calling-convention

  

可能重复:
  Using a C++ class member function as a C callback function

我正在使用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的第3个参数)。由于这是第三方代码,我无法真正改变这一点。我必须有一个可以采用这种形式的成员函数:

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

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

请参阅有关

的详细主题

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

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

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

答案 2 :(得分:3)

如果你想让C API调用成员函数,你必须传递 两个 数据:(静态成员)函数和对象它是被调用的。

通常,C API回调具有某种形式的“用户数据”,通常是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);
}

与全局数据一样,如果回调的多个实例存活,则这是危险的。我试图尽量减少伤害,以便在它们的生命周期嵌套时起作用。但是,其他任何事情都会受到伤害。