回调函数是通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是实现该函数的软件模块直接调用,而是在特定的事件或条件发生时由另外的软件模块通过函数指针的方式调用,用于对该事件或条件进行响应,是一种下层软件模块调用上层软件模块的特殊方式。
给Linktable增加Callback方式的接口,需要两个函数接口,一个是call-in方式函数,如SearchLinkTableNode函数,其中有一个函数作为参数,这个作为参数的函数就是callback函数,即代码中conditon函数。由于我们在工程化C编程中追求松散耦合,所以给call-in方式的函数接口SearchLinkTableNode增加了一个参数args,Callbackfunc函数conditon也增加了一个参数args。args用于传递用户输入的菜单命令(help、version和quit)。
typedef int(*Callbackfunc)(tLinkTableNode *pNode, void *args);
/*
* Serach a LinkTableNode from LinkTable
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, Callbackfunc conditon, void * args);
实现代码如下:
/*
* Serach a LinkTableNode from LinkTable
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable,
Callbackfunc condition,
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,例如下面的SearchCondition:
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;
}