工程化编程实战callback接口学习笔记
一、实验要求
1.在VSCode下编译运行lab5-1.tar.gz
2.通过VSCode+GDB调试程序找出quit命令无法运行的bug产生的原因
3.分析callback接口的运行机制,总结callback接口设计的方法
二、实验过程
首先需要在 menu.c 中添加头文件 string.h,在 vscode 中,打开 terminal, 输入指令:gcc -o test linktable.c menu.c,随后 ./test 运行
可以输入三个参数 help、version 和 quit,其中 quit 无法运行

经过分析找到输出 This is a wrong cmd! 的代码段,可知错误由 p == null 引起的,
tDataNode *p = FindCmd(head, cmd); if(p == NULL) { printf("This is a wrong cmd!\n"); continue; }
以上可以看出,当 p 为 NULL 时返回错误信息。
进一步查看 FindCmd 函数:
/* find a cmd in the linklist and return the datanode pointer */ tDataNode *FindCmd(tLinkTable *head, char *cmd) { return (tDataNode*)SearchLinkTableNode(head, SearchCondition); }
再进一步查看 SearchLinkTableNode 函数,该函数的第二个参数为一个函数指针,即回调函数。
// 把 Condition 修改为了函数指针,更容易理解 tLinkTableNode *SearchLinkTableNode(tLinkTable *pLinkTable, int (*Conditon)(tLinkTableNode *pNode)) { if(pLinkTable == NULL || Conditon == NULL) { return NULL; } tLinkTableNode *pNode = pLinkTable->pHead; while(pNode != pLinkTable->pTail) { if(Conditon(pNode) == SUCCESS) { return pNode; } pNode = pNode->pNext; } return NULL; }
经过分析可得:while 的终止条件为 pNode == pLinkTable->pTail(pNode 等于链表最后一个结点时终止),而从链表初始化函数中可看出,quit 刚好为链表最后一个结点,因此链表内的 quit 还没机会与输入命令进行比较就已经终止循环。因此,修改循环条件为 pNode != NULL。
之后再进行编译和运行:

三.回调函数
回调函数的定义:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
回调机制的优势
乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。
所以,我们可以利用回调函数,使函数拥有更强的灵活性与更松散的耦合,对于长久代码模块化,开发,维护都更加有利。
浙公网安备 33010602011771号