工程化编程实战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 运行

 可以输入三个参数 helpversion 和 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->pTailpNode 等于链表最后一个结点时终止),而从链表初始化函数中可看出,quit 刚好为链表最后一个结点,因此链表内的 quit 还没机会与输入命令进行比较就已经终止循环。因此,修改循环条件为 pNode != NULL。

之后再进行编译和运行:

 

 

三.回调函数

回调函数的定义:

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

回调机制的优势

乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。

所以,我们可以利用回调函数,使函数拥有更强的灵活性与更松散的耦合,对于长久代码模块化,开发,维护都更加有利。

posted @ 2020-03-19 11:36  lwjing  阅读(115)  评论(0)    收藏  举报