回调函数与静态函数与this指针


前言

  最近在做linux下的网络抓包程序,使用的libpcap库,里面很方便的提供了pcap_loop这个循环函数,在用C语言编写调试后,运行没有任何问题,但是在面向对象编程的过程中,此函数调用回掉函数,编译会产生不可调和错误,写这篇博文分享给有相似遭遇的朋友参考,其中部分内容引用了其他博友的观点。
   


显示错误

xxx/net.h:418: error: cannot convert ‘Netthread::ethernet_packet_callback’ from type ‘void (Netthread::)(unsigned char*, const pcap_pkthdr*, const unsigned char*)’ to type ‘pcap_handler {aka void ()(unsigned char, const pcap_pkthdr*, const unsigned char*)}’pcap_loop(pt, -1, ethernet_packet_callback, NULL);                           

或者

xxx/net.h:420: error: cannot convert ‘Netthread::ethernet_packet_callback’ from type ‘pcap_pkthdr*(Netthread::)(unsigned char*, const pcap_pkthdr*, const unsigned char*)’ to type ‘pcap_handler {aka void ()(unsigned char, const pcap_pkthdr*, const unsigned char*)}’ pcap_loop(pt, -1, ethernet_packet_callback, NULL);

错误原因:

  如果试图直接使用c++的成员函数作为回调函数将会发生错误,甚至编译就不能通过。其错误的原因是普通的c++成员函数都隐含了一个传递函数作为 参数,亦即“this”指针,由于this指针的作用,使得回掉函数与普通的C++成员函数参数个数不匹配,从而导致回调函数安装失败。要解决这一问题的 关键就是不让this指针起作用,通过采用解决办法一、二两种典型技术可以解决在C++中使用回调函数所遇到的问题,如果没有解决,使用方法三。


解决办法一

利用全局函数来实现回调函数,因为全局函数不属于任何类。那当然就不再拥有this指针,配合一个全局缓冲区则可以实现全局函数与捕获窗口的数据通信。

解决办法二

利用静态成员函数机制来实现,静态成员函数不使用this指针作为隐含参数,满足回调函数的条件,但是不能访问非静态成员变量。为了实现与捕获窗口的数据通信可以通过使用一个静态类指针作为类成员,通过在类创建时初始化该静态指针,如QThis—this,然后在回调函数中就可以通过该静态指针访问所 有成员变量和成员函数了。

解决办法三

此方法针对libpcap库里的pcap_loop()函数里的回掉函数。
问题如下:
pcap_loop参数如下:

pcap_loop(pcap_t *,int,pcap_hander callback,u_char *);

callback参数

callback (u_char *,const pcap_pkthdr *,const u_char *);

pcap_loop作用是,每来一个数据包,调用一次callback函数。
但是问题在于,callback(回调函数)并不能被定义成类的成员,一旦定义成类的成员,编译便会报错。

使用解决方法一的问题在于,一旦把callback定义成全局,那么callback将无法访问类内成员。当然我们可以尝试把类取消,但是鉴于我要使用线程机制,并且QT里面的线程是继承于QThread类,所以类无法省略,此方法行不通。

使用解决方法二的问题在于,把callback设为静态成员函数,则无法访问类内非静态成员,当然我第一想法是把所有成员均设为静态,以此来访问,但此方法在后来试验中出现了很多问题。

为了达成效果,只得想第三种办法,从源程序下手,避开回掉函数。
不使用pcap_loop()函数,从而也就不涉及到回掉函数问题。

替代方法
libpcap库里有 pcap_next()方法。
使用此函数循环抓取,也能达到相同效果。
使用方法如下:

while(stopped){
    packet=(unsigned char *)pcap_next(pt,&hdr);
    if(packet==NULL)
        continue;
    else{
        printf("get a packet/n");
        ethernet_packet_callback(NULL,&hdr,packet);//这不是回调函数,我只是没改名字
    }
}

虽然在纯c程序中,使用pcap_loop确实会省事一些,但移植到面向对象相关编程时,问题很麻烦。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值