工程化编程实战callback接口学习笔记

一、实验目的

  • 在VSCode下编译运行lab5-1.tar.gz 即http://pan.baidu.com/s/1pJ0qAIv

  • 通过VSCode+GDB调试程序找出quit命令无法运行的bug产生的原因

  • 分析callback接口的运行机制,总结callback接口设计的方法

二、实验过程

  1、运行menu.c,找出错误的运行结果。

运行结果为:

工程化编程实战callback接口学习笔记_第1张图片

 

 

查看结果,使用quit发现没有退出程序,而是提示worng cmd,显然是错误的。

  2、查看源文件中“Input a cmd number”所在位置,从而定位以下代码

 1 while(1)
 2 {
 3   printf("Input a cmd number > ");
 4   scanf("%s", cmd);
 5   tDataNode *p = FindCmd(head, cmd);
 6   if( p == NULL)
 7   {
 8     printf("This is a wrong cmd!\n ");
 9     continue;
10   }
11   printf("%s - %s\n", p->cmd, p->desc);
12   if(p->handler != NULL)
13   {
14     p->handler();
15   }
16 }

观察代码可知,输出“wrong cmd”的判断语句是p与NULL的关系,指针p指向空,导致quit命令输出结果错误。

而观察第5行可知,指针p是FindCmd()函数的返回值。

  3、观察FindCmd()函数。

1 tDataNode* FindCmd(tLinkTable * head, char * cmd)
2 {
3     return  (tDataNode*)SearchLinkTableNode(head,SearchCondition);
4 }

发现其调用SearchLinkTableNode()函数。

 1 /*
 2  * Search a LinkTableNode from LinkTable
 3  * int Conditon(tLinkTableNode * pNode);
 4  */
 5 tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode))
 6 {
 7     if(pLinkTable == NULL || Conditon == NULL)
 8     {
 9         return NULL;
10     }
11     tLinkTableNode * pNode = pLinkTable->pHead;
12     while(pNode != pLinkTable->pTail)
13     {    
14         if(Conditon(pNode) == SUCCESS)
15         {
16             return pNode;                    
17         }
18         pNode = pNode->pNext;
19     }
20     return NULL;
21 }

从SearchLinkTableNode()源码可以看出:

返回NULL的条件有三个:

(1) pLinkTable == NULL ---  不会出现该种情况

(2) Conditon == NULL ---  也不会出现该种情况

(3) pNode == pLinkTable->pTail ---  唯一出现NULL的可能

  4、pTail是什么?

观察结构体:

工程化编程实战callback接口学习笔记_第2张图片

 

 

 添加结点时对pTail成员的处理:

 1 /*
 2  * Add a LinkTableNode to LinkTable
 3  */
 4 int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)
 5 {
 6     if(pLinkTable == NULL || pNode == NULL)
 7     {
 8         return FAILURE;
 9     }
10     pNode->pNext = NULL;
11     pthread_mutex_lock(&(pLinkTable->mutex));
12     if(pLinkTable->pHead == NULL)
13     {
14         pLinkTable->pHead = pNode;
15     }
16     if(pLinkTable->pTail == NULL)
17     {
18         pLinkTable->pTail = pNode;
19     }
20     else
21     {
22         pLinkTable->pTail->pNext = pNode;
23         pLinkTable->pTail = pNode;
24     }
25     pLinkTable->SumOfNode += 1 ;
26     pthread_mutex_unlock(&(pLinkTable->mutex));
27     return SUCCESS;        
28 }

由上可知:在链表添加代码时,pTail总会指向链表的最后一个节点。所以p == NULL是因为pNode指向链表的最后一个节点不满足循环条件,直接退出while循环。

while循环条件while(pNode != pLinkTable -> pTail)使得函数在找到链表最后一个节点时即退出循环,因此无法访问最后一个节点,而退出的话需要找到最后的节点,所以我们可以将错误代码while(pNode != pLinkTable -> pTail)改为while(pNode != NULL)来解决bug。

三、总结

回调函数:就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

你可能感兴趣的:(工程化编程实战callback接口学习笔记)