一、运行示例
起初笔者没有注意到makefile文件,在windows系统下做实验如何调试都不行,直到看到rm -rf操作。。。
于是,笔者用vscode远程连接到linux系统中编译调试
成功运行!
二、分析回调函数
首先,我们分析头文件中的结构体,linktableInternel.h文件中定义了LinkTableNode(具体的每一个节点)和LinkTable(表的结构),具体定义如下:
struct LinkTableNode
{
struct LinkTableNode * pNext;
};
struct LinkTable
{
struct LinkTableNode *pHead;
struct LinkTableNode *pTail;
int SumOfNode;
pthread_mutex_t mutex;
};
由LinkTableNode连接成整个Table。
而在menu.c文件中又定义了tDataNode节点:
typedef struct DataNode
{
tLinkTableNode head;
char* cmd;
char* desc;
int (*handler)();
} tDataNode;
tDataNode中会保存tLinkTableNode结构的信息,而连接链表时又是提取其中的head成员进行操作,从而能够压缩该数据结构的存储空间,同时实现业务和数据的分离,当需要用到具体指令及其他信息时进行类型强制转换,如下所示:
int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
char * cmd = (char*) args;
tDataNode * pNode = (tDataNode *)pLinkTableNode;
if(strcmp(pNode->cmd, cmd) == 0)
{
return SUCCESS;
}
return FAILURE;
}
回调函数是通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是实现该函数的软件模块直接调用,而是在特定的事件或条件发生时由另外的软件模块通过函数指针的方式调用,用于对该事件或条件进行响应,是一种下层软件模块调用上层软件模块的特殊方式。回调函数应用场景的简要示意图如下所示
以上内容来自博客参考
从main函数进入时,首先会初始化链表,将help,version,quit命令依次添加到链表中,然后根据用户输入的命令,调用FindCmd函数,到指定功能。
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
return (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)cmd);
}
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable,
int Condition(tLinkTableNode * pNode, void * args),
void * args)
{
if(pLinkTable == NULL || Condition == NULL)
{
return NULL;
}
tLinkTableNode * pNode = pLinkTable->pHead;
while(pNode != NULL)
{
if(Condition(pNode, args) == SUCCESS)
{
return pNode;
}
pNode = pNode->pNext;
}
return NULL;
}
其中,SearchLinkTableNode是call-in函数,其中有一个函数作为参数,这个作为参数的函数就是callback函数,即其中有一个函数作为参数,这个作为参数的函数就是callback函数,即代码中Conditon函数。具体到该业务应是SearchCondition函数,可以看到if(Condition(pnode,args)==SUCCESS)这句话中调用了callback函数,为了实现松散耦合,加入args参数,在本例中,在调用时会将void转成char类型,callback函数可以用来定制LinkTable的功能,通过将callback函数作为参数传递,可以实现代码的复用和扩展性。