C++ 如何将指向成员函数的指针传递给C函数?
可能重复:C++ 如何将指向成员函数的指针传递给C函数?,c++,c,function-pointers,winpcap,calling-convention,C++,C,Function Pointers,Winpcap,Calling Convention,可能重复: 我正在使用C库(winpcap)编写一个面向对象的库。我需要传递当网络数据包作为函数指针到达时调用的回调函数。我想传递一个成员函数指针到winpcap,以保持我的设计面向对象,并允许不同的对象接收不同的数据包。然而,据我所知,成员函数具有不同的调用约定,因此不能传递给C函数。有没有办法解决这个问题。我对boost::bind的实验(除了尝试和错误之外,我几乎无法使用它)没有什么成果 有没有办法改变成员函数的调用约定 这是我现在使用的回调函数的定义,以及它实际传递给winpcap的过
我正在使用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_循环只取函数名(目前在全局范围内)。这是函数指针参数(的第三个参数)的定义。因为这是第三方代码,所以我不能真正更改它。我必须有一个成员函数,可以采用以下形式:
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);
据我所知,成员函数将使用此调用,而c函数指针需要一个cdecl您只能将
静态
成员函数传递给c API。如果您想让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);
}
与全局数据一样,如果回调的多个实例处于活动状态,则这是危险的。我试着把伤害降到最低,这样如果它们的生命是嵌套的,它就会起作用。不过,其他任何事情都会造成伤害 请参考关于
<强>如何实现静态C++成员函数的回调?<强> < /P>
<强>如何实现对非静态C++成员函数的回调?<强> < /P>
和的副本。谢谢,我没有找到那个。好吧,这是不正确的,请参阅其他答案和重复问题的答案。解决这个问题有很多方法,这些方法正是我想要的。@ufotds:虽然确实可以使用巧妙的技巧使
静态
成员函数调用非静态
成员函数,但也确实只能将(指向)静态
成员函数的指针传递给C API。所以Paul确实是对的,虽然这比他写的要多。好的,显然我问题的标题应该提到一个非静态成员函数。。。在这方面,静态函数与调用成员函数的全局函数一样好(稍微好一点)。当你处理像glutDisplayFunc这样的函数时,这会很痛苦,它的回调函数是void(u cdecl*)(void);因此,display进程无法知道是谁调用了它,而不会不可避免地造成竞争条件或要求使用锁(因为如果不将调用方存储在全局状态,或者不使用全局状态将函数的地址映射到它的前一个调用方,就无法让不同的回调确定调用它们的人,但这样做意味着更改此映射可能会导致数据争用)@Dimitry:如果C API回调没有提供用户提供的参数,那么它要么不打算与某些特定数据块结合使用,要么API创建者很笨。不管怎样,你都需要编写一个自由函数。是的,但是不管怎样,当用户想在glut之上编写库时,他们将无法让display被使用意识到他们的场景图没有一个本地的,或者未来可能的比赛。
// 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);
}