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

 

实验环境:

Windows10+VS code+MinGW64

 

编译运行lab5-1.tar.gz:

先后安装vscode, Microsoft C/C++ extension, Mingw-w64,然后配置环境变量,配置完成后结果如下:

 工程化编程实战callback接口学习笔记_第1张图片

 

 

 

运行lab5.1:

 工程化编程实战callback接口学习笔记_第2张图片

 

 

配置pthread.h

 

 

 

 

出错,添加头文件string.h

程序运行后,输入“help”,输入“version”输出正常,输入“quit”却显示命令不合法。

 工程化编程实战callback接口学习笔记_第3张图片

 

 

 

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

观察menu.c的main函数,当p == NULL,显示This is a wrong cmd!

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();
        }
   
    }
}

 使用gdb设置断点,分析为何quit出错

 

quit调用FIndCmd函数,而FindCmd函数又调用SearchLinkTableNode函数

tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    return  (tDataNode*)SearchLinkTableNode(head,SearchCondition);

 

SearchLinkTableNode函数代码如下:

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;
}

可以看到,因为pNode != pLinkTable->pTail,当遍历到pLinkTable的尾结点时,也直接返回空,而没有对尾结点的Condition值进行判断。

 

观察InitMenuData函数我们可以看到,指令“quit”所在的节点恰好是链表的尾结点:

int InitMenuData(tLinkTable ** ppLinktable)
{
    *ppLinktable = CreateLinkTable();
    tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "help";
    pNode->desc = "Menu List:";
    pNode->handler = Help;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "version";
    pNode->desc = "Menu Program V1.0";
    pNode->handler = NULL; 
    AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "quit";
    pNode->desc = "Quit from Menu Program V1.0";
    pNode->handler = Quit; 
    AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);
 
    return 0; 
}

因此,只需将while循环的条件改为“while(pNode != pLinkTable->pTail->pNext)”即可。

重新编译则运行成功。

 

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

 

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

callback方法特点是将回调函数以参数的形式将函数指针传递给另一个中间函数,可以提高代码重用度,提高编程的灵活性以及编程效率。

如linktable.c中的SearchLinkTableNode函数:tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode));其有一个参数是函数int Conditon(tLinkTableNode * pNode),这个作为参数的Condition函数即为callback函数。

 

你可能感兴趣的:(工程化编程实战callback接口学习笔记)