小甜、
Published on 2017-09-02 11:31 in 暂未分类 with 小甜、

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

作业要求

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

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

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

具体实现

1. 环境准备

  1. 首先安装MAC环境下的GCC

  2. 打开VSCode,通过Ctrl+Shift+x 安装C/C++调试器

  3. 下载作业要求中的lab5-1.tar.gz文件

2. 文件运行

  1. 打开VSCode命令行,使用如下命令编译程序,生成可执行文件
gcc -o test menu.c linktable.c

结果如下:

根据提示发现文件缺少函数strcmp所在的头文件,在menu.c中添加string.h头文件,继续编译后

  1. 编译成功,执行编译后文件,输入指令./test,进一步输入help和quit指令,结果如下:

3. 调试

  1. 定位main函数,代码如下:
int main()
{
    InitMenuData(&head); 
   /* cmd line begins */
    while(1)
    {
        printf("Input a cmd number > ");
        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();
        }
   
    }
}

发现通过调用FindCmd()函数进行指令具体操作,进一步找到该函数的调用函数如下:

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode))
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
//部分代码

我们能够看到,调用该查找函数传入的参数为InitMenuData(&head)链表和我们输入的cmd命令,我们来检查一下直接返回空指针只有在pLinkTable和Conditon至少有一个为空的时候,很明显这是我们的输入和cmd命令,并不为空,让我们继续看另外一种情况

//承接上部分代码 
while(pNode != pLinkTable->pTail)
    {   
        if(Conditon(pNode) == SUCCESS)
        {
            return pNode;                   
        }
        pNode = pNode->pNext;
    }
    return NULL;
}

另一种情况就是直到pNode循环遍历结束以后也未满足Conditon(pNode) == SUCCESS的条件,那么我们来看看pLinkTable->pTai

 else
    {
        pLinkTable->pTail->pNext = pNode;
        pLinkTable->pTail = pNode;
    }
    pLinkTable->SumOfNode += 1 ;
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return SUCCESS;  

不难发现,在判断是否为末尾的时候并未判断Conditon(pNode) == SUCCESS,而直接返回空指针,我们将SearchLinkTableNode函数修改如下(改为判断只有不为空的时候才进行遍历):

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode))
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)     
    {   
        if(Conditon(pNode) == SUCCESS)
        {
            return pNode;                   
        }
        pNode = pNode->pNext;
    }
    return NULL;
}

重新编译运行,结果如下:

Callback接口

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。


可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。

posted @ 2020-03-18 22:08  小甜、  阅读(91)  评论(0编辑  收藏  举报