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

1.1、运行环境linux,编译工具gcc,实验代码lab5-1.tar.gz http://pan.baidu.com/s/1pJ0qAIv

1.2、使用gcc编译程序linktable.cmenu.c,即使用命令gcc -o test linktable.c menu.c,将linktablemenu.c编译成可执行文件,名为test

注意需要在menu.c的头文件中加入#include<string.h>,否则报错缺失相关库。

1.3、输入./test运行之前编译的程序,然后在程序中输入help查看程序提供的命令参数,但是发现输入quit时,程序没有识别出该命令。

 

 

2问题发现和程序修改

 2.1、可以首先定位到menu.c的主函数main中,发现当tDataNode 类型的指针pNULL时,报出This is a wrong cmd!信息,而指针p的值来源于函数FindCmd函数,观察FindCmd程序,可以继续定位到linktable.c文件中的SearchLinkTableNode函数。

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! ");

            continue;

        }

        printf("%s - %s ", p->cmd, p->desc);

        if(p->handler != NULL)

        {

            p->handler();

        }

   

    }

}

tDataNode* FindCmd(tLinkTable * head, char * cmd)

{

    return  (tDataNode*)SearchLinkTableNode(head,SearchCondition);

}

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;

}

该函数的两个参数分别表示由命令参数组成的链表头指针和当前命令是否找到,以下情况返回NULL:

pLinkTable == NULL

Conditon == NULL

该链表中所有节点的Condition都不为SUCCESS

调试程序,发现只有当pNode != pLinkTable->pTail条件为真时,不断的遍历链表上的节点信息,来对比用户输入的命令从而返回相应节点。所以继续定位到该循环,发现循环条件比较奇怪,我们继续调试这个条件,观察链表的结构和链表的添加节点操作。

tLinkTable * CreateLinkTable()

{

    tLinkTable * pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));

    if(pLinkTable == NULL)

    {

        return NULL;

    }

    pLinkTable->pHead = NULL;

    pLinkTable->pTail = NULL;

    pLinkTable->SumOfNode = 0;

    pthread_mutex_init(&(pLinkTable->mutex), NULL);

    return pLinkTable;

}

int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode)

{

    if(pLinkTable == NULL || pNode == NULL)

    {

        return FAILURE;

    }

    pNode->pNext = NULL;

    pthread_mutex_lock(&(pLinkTable->mutex));

    if(pLinkTable->pHead == NULL)

    {

        pLinkTable->pHead = pNode;

    }

    if(pLinkTable->pTail == NULL)

    {

        pLinkTable->pTail = pNode;

    }

    else

    {

        pLinkTable->pTail->pNext = pNode;

        pLinkTable->pTail = pNode;

    }

    pLinkTable->SumOfNode += 1 ;

    pthread_mutex_unlock(&(pLinkTable->mutex));

    return SUCCESS;        

}

分析上面的代码可以发现pLinkTable->pTail代表的是链表的最后一个节点的指针,这下在回到SearchLinkTableNode函数中的循环,发现当链表到达最后节点是就不再循环了,即并没有判断最后一个节点的Condition,中途停止返回空。

2.2、修改程序消除bug

知道了指针返回为空的原因是没有彻底遍历链表中的所以节点,漏了最后一个节点,所以我们修改循环条件

pNode != pLinkTable->pTailpNode != pLinkTable->pTail-pNextpNode != NULL

 修改后重新编译运行测试成功

 

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

在计算机程序设计中,回调函数,或简称回调(Callback call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。(这是维基百科定义)

回调函数通常和原始调用者处于同意抽象层

回调函数实现的多态的机制,通过注册不同的函数到同一个类的不同对象中,可以事项多态的机制。

回调函数的实现方法

在类中声明函数指针,可以对函数进行绑定

类创建对象时,对对象中的函数指针进行绑定

通过对象,调用绑定的函数,实现回调机制。

原文地址:https://www.cnblogs.com/buzhidao1/p/12516713.html