1.实验要求
-
在VSCode下编译运行lab5-1.tar.gz 即http://pan.baidu.com/s/1pJ0qAIv
-
通过VSCode+GDB调试程序找出quit命令无法运行的bug产生的原因
- 分析callback接口的运行机制,总结callback接口设计的方法
2.实验过程:
编译报错:
源代码定位问题:
p == NULL为真的情况下,程序会报错wrong cmd。因为p是FindCmd函数的返回值,因此找到FindCmd的函数定义,如下:
发现FindCmd只是对SearchLinkTableNode进行了包装,因此继续查看SearchLinkTableNode()函数的定义
光看这里我们发现有可能是pLinkTable或者Condition为空,也可能是执行到函数末尾返回空。首先返回menu.c查看pLinkTable是否有可能为空。因为pLinkTable实际上就是menu.c的全局变量head,又发现head在InitMenuData函数中进行了初始化,如下所示。因此pLinkTable不为空。
又因为Condition函数同样在menu.c给出,因此NULL是在函数末尾处返回的。所以我们需要去研究一下链表是怎么构造的。通过上图InitMenuData()函数,我们得知构造链表是通过AddLinkTableNode()进行的。如下:
我们发现,每次插入节点之后,pTail指向的是最后一个节点,所以是while循环的判断条件出现了问题,导致pNode没有与链表的最后一个节点比较,导致我们的quit命令没有反应。综上,修改while语句的判断条件即可:
之后重新编译运行:
顺利退出。
3.分析callback接口的运行机制
1 回调函数的运行机制
回调函数是指使用者自己定义一个函数,实现这个函数的程序内容,然后把这个函数(入口地址)作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数。函数是你实现的,但由别人(或系统)的函数在运行时通过参数传递的方式调用,这就是所谓的回调函数。简单来说,就是由别人的函数运行期间来回调你实现的函数。
这一设计允许了底层代码调用在高层定义的子程序。C语言中回调函数主要通过函数指针的方式实现。
本例中使用了回调函数的机制,本例中FindCmd(tLinkTable * head, char * cmd)调用SearchLinkTableNode(head,SearchCondition)函数,而SearchLinkTableNode通过调用了回调函数condition()。实现函数调用中,函数调用了“调用函数”,再在其中进一步调用被“调用函数”。相比于主函数直接调用“被调函数”,这种方法为使用者,而不是开发者提供了灵活的接口。另外,函数入口可以像变量一样设定同样为开发者提供了灵活性。
2 Callback接口设计的方法
- 回调函数传入的参数是函数指针,函数指针用来调用其所指向的函数,调用者和被调用者分开,调用者并不关心谁是被调用者,可以对特定的事件或条件进行响应,当发生某种事件时系统或其他函数会自动调用定义的一段函数。
- 将符合要求的参数以及函数指针作为调用函数的参数。当用户调用时,只需要将函数指针指向不同的函数即可