QT中是有信号槽,发现挺好用,秉承着好用就使劲用的原则,肯定要记录下。其实早就有博主实现了轮子。
实现的博主链接:https://mp.weixin.qq.com/s/3BcMHY71lH3WPgcPwxb2LQ,但是测试用例描述的不太清晰,自己写了测试下了。
实验代码:
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define __PLOOC_CLASS_USE_STRICT_TEMPLATE__
#if defined(__SIGNALS_SLOTS_CLASS_IMPLEMENT__)
#define __PLOOC_CLASS_IMPLEMENT__
#elif defined(__SIGNALS_SLOTS_CLASS_INHERIT__)
#define __PLOOC_CLASS_INHERIT__
#endif
#include "plooc_class.h"
#define SIG_NAME_MAX 20
#define SIGNAL(x) "sig_"#x
#define SLOT(x) x
#define SIG_SLOT_OBJ sig_slot_t tObject;
#define args(...) ,__VA_ARGS__
#define _args(...) __VA_ARGS__
#define __RecFun_0(__OBJ) \
__RecFun((__OBJ))
#define __RecFun_1(__OBJ, __ARG1) \
__RecFun((__OBJ),(__ARG1))
#define __RecFun_2(__OBJ, __ARG1, __ARG2) \
__RecFun((__OBJ),(__ARG1), (__ARG2))
#define __RecFun_3(__OBJ, __ARG1, __ARG2, __ARG3) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3))
#define __RecFun_4(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4))
#define __RecFun_5(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5))
#define __RecFun_6(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6))
#define __RecFun_7(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6, __ARG7) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6), (__ARG7))
#define __RecFun_8(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6, __ARG7, __ARG8) \
__RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6), (__ARG7), (__ARG8))
#define __signals(__NAME,...) \
typedef void PLOOC_CONNECT2(__NAME,_fun_t)( __VA_ARGS__);
#define signals(__NAME,__OBJ,...) \
__signals(__NAME,_args(__OBJ __VA_ARGS__))
#define __emit(__OBJ,...) \
__PLOOC_EVAL(__RecFun_,##__VA_ARGS__) \
((__OBJ)->ptRecObj,__VA_ARGS__);
#define emit(__NAME,__OBJ,...) \
do {sig_slot_t *ptObj = &((__OBJ)->tObject); \
do{if(__OBJ == NULL || ptObj == NULL ) break; \
PLOOC_CONNECT2(__NAME,_fun_t) *__RecFun = ptObj->ptRecFun; \
if(__RecFun != NULL) __emit(ptObj __VA_ARGS__); \
ptObj = ptObj->ptNext; \
}while(ptObj != NULL); \
}while(0)
#define __slots(__NAME,...) \
void __NAME(__VA_ARGS__);
#define slots(__NAME,__OBJ,...) \
__slots(__NAME,_args(__OBJ,##__VA_ARGS__))
#define connect(__SIG_OBJ,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN) \
direct_connect(__SIG_OBJ.tObject,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)
#define connectptr(__SIG_OBJ,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN) \
direct_connect(&__SIG_OBJ->tObject,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)
#define disconnect(__SIG_OBJ,__SIG_NAME) \
auto_disconnect(__SIG_OBJ.tObject,__SIG_NAME)
#define disconnectptr(__SIG_OBJ,__SIG_NAME) \
auto_disconnect(&__SIG_OBJ->tObject,__SIG_NAME)
typedef struct sig_slot_t sig_slot_t;
typedef struct sig_slot_t{
char chSenderName[SIG_NAME_MAX];
void * ptSenderObj;
void * ptRecObj;
void * ptRecFun;
sig_slot_t *ptNext;
sig_slot_t *ptPrev;
}sig_slot_t;
void direct_connect(sig_slot_t *ptSenderObj, const char *ptSender,void *ptRecObj,void *ptRecFun);
void auto_disconnect(sig_slot_t *ptSenderObj, const char *ptSender);
#undef __SIGNALS_SLOTS_CLASS_INHERIT__
#undef __SIGNALS_SLOTS_CLASS_IMPLEMENT__
void direct_connect(sig_slot_t *SenderObj, const char *ptSender,void *RecObj,void *RecFun)
{
if(SenderObj == NULL || ptSender == NULL || RecObj == NULL || RecFun == NULL){
return;
}
sig_slot_t * ptMetaObj = SenderObj;
do{
if(strstr(RecFun,"sig_")){
memcpy(ptMetaObj->chSenderName,ptSender,strlen(ptSender));
while(ptMetaObj->ptNext != NULL){
ptMetaObj = ptMetaObj->ptNext;
}
ptMetaObj->ptNext = RecObj;
ptMetaObj->ptNext->ptPrev = ptMetaObj;
ptMetaObj = ptMetaObj->ptNext;
memcpy(ptMetaObj->chSenderName,RecFun,strlen(RecFun));
break;
}
if(strcmp(ptMetaObj->chSenderName,ptSender) == 0){
sig_slot_t * ptSenderObj = malloc(sizeof(sig_slot_t));
while(ptMetaObj->ptNext != NULL){
ptMetaObj = ptMetaObj->ptNext;
}
ptMetaObj->ptNext = ptSenderObj;
ptMetaObj->ptNext->ptPrev = ptMetaObj;
ptMetaObj = ptMetaObj->ptNext;
}
ptMetaObj->ptRecFun = RecFun;
ptMetaObj->ptRecObj = RecObj;
memcpy(ptMetaObj->chSenderName,ptSender,strlen(ptSender));
}while(0);
}
void auto_disconnect(sig_slot_t *ptSenderObj, const char *ptSender)
{
if(ptSenderObj == NULL || ptSender == NULL){
return;
}
sig_slot_t * ptMetaObj = ptSenderObj;
if(strcmp(ptMetaObj->chSenderName,ptSender) == 0){
while(ptMetaObj->ptNext != NULL){
ptMetaObj = ptMetaObj->ptNext;
}
while(ptMetaObj != NULL){
ptMetaObj->ptNext = NULL;
memset(ptMetaObj->chSenderName,0,sizeof(ptMetaObj->chSenderName));
if(ptMetaObj->ptRecFun != NULL){
ptMetaObj->ptRecObj = NULL;
ptMetaObj->ptRecFun = NULL;
sig_slot_t * ptObj = ptMetaObj;
free(ptObj);
}
ptMetaObj = ptMetaObj->ptPrev;
}
}
}
typedef struct
{
SIG_SLOT_OBJ
int a;
int b;
int c;
}test;
test m_test;
//signals(send_sig,test* this,args(unsigned char* p,int len));
typedef struct
{
int c;
}rslot;
rslot m_slot;
void func(void *this, unsigned char* p,int len)
{
printf("----%p\n",this);
printf("p is %s c is %d\n",p,len);
return;
}
signals(send_sig,test* this,args(unsigned char* p,int len));
int main(int argc, char* argv[])
{
m_test.a =1;
m_test.b =2;
m_test.c =3;
rslot* cc_slot = &m_slot;
test* cc_test = (test*) malloc(sizeof(test));
printf("func %p\n",func);
printf("cc_test addr %p\n",cc_test);
connectptr(cc_test,SIGNAL(send_sig),&m_slot,SLOT(func));
printf("----%p\n",&m_slot);
unsigned char cc[30] = {"hello"};
emit(send_sig,cc_test,args(cc,m_test.b));
disconnectptr(cc_test,SIGNAL(send_sig));
return 0;
}
运行结果:
潜在的隐患:
若信号槽传入的参数是malloc分配的,需要在168行进行free释放