回调函数
回调函数是一个通过函数指针调用的函数。将函数的指针作为参数传递给另一个函数,当函数使用这个指针时,会调用此指针所指向的函数,即回调函数。回调函数不是由实现该函数的实现者直接调用,而是在特定的事件或条件发生时由另外的一方通过函数指针的方式调用,用于对该事件或条件进行响应。是一种下层软件模块调用上层软件模块的特殊方式。
代码分析
我们在 Linktable 中增加 Callback 方式的接口。这里需要两个函数接口,一个是 call-in 方式函数,即 SearchLinkTableNode 函数。
/*
* Search a LinkTableNode from LinkTable
* int Conditon(tLinkTableNode * pNode, void * args);
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args);
在此函数中,第二个参数是一个函数指针,传入一个 Condition 的函数,即 call-back 方式函数。给 call-in 方式的函数 SearchLinkTableNode 增加了一个参数 args,call-back 方式的函数 Conditon 也增加了一个参数 args,用于传递用户输入的菜单命令。
通过将指定的函数传入,使用业务定制化查询条件进行查询,进行解耦,将工具代码和业务代码逻辑分开。
该接口对应的实现代码如下
/*
* Serach a LinkTableNode from LinkTable
* int Condition(tLinkTableNode *pNode, void * args);
*/
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;
}
可以看到,该代码中并没有实现 Condition 函数。Condition 只是业务代码传进来的一个函数指针,我们在回调函数接口定义时规定了传进来的函数指针的规格。
再来看 menu 菜单项目中采用 Callback 方式的函数接口来查询链表的代码。
typedef struct DataNode
{
tLinkTableNode head;
char* cmd;
char* desc;
int (*handler)();
}tDataNode;
int SearchCondition(tLinkTableNode *pLinkTableNode, void *args)
{
char * cmd = (char*) args;
tDataNode * pNode = (tDataNode *)pLinkTableNode;
if (strcmp(pNode->cmd, cmd) == 0)
{
return SUCCESS;
}
return FAILURE;
}
/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
return (tDataNode *)SearchLinkTableNode(head, SearchCondition, (void *)cmd);
}
main 函数中调用 FindCmd 函数的代码。
int main()
{
InitMenuData(&head);
/* cmd line begins */
while (1)
{
char cmd[CMD_MAX_LEN];
printf("Input cmd > ");
scanf("%s", cmd);
tDataNode *p = FindCmd(head, cmd);
if (p == NULL)
{
printf("This is a wrong cmd!\n");
continue;
}
printf("%s - %s\n", p->cmd, p->desc);
if (p->handler != NULL)
{
p->handler();
}
}
return 0;
}
回调函数工作流程大致如下图所示。