ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2020-03-15 21:51:31  阅读:311  来源: 互联网

标签:pTail 函数 callback 编程 pNode pLinkTable 工程化 NULL 指针


一、实验要求

  • 在VSCode下编译运行lab5-1.tar.gz 

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

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

二、实验过程

      首先安装好vscode和MinGW并配置好环境变量。

      在vscode下导入实验所需要的代码,点击debug按钮,添加配置,选择C/C++ gdb启动,配置好launch.json和tasks.json,

编译运行,按要求输入quit命令,发现输出为This is a wrong cmd!

      我们来检查一下menu.c的源码:

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

      很明显可以看到由于p为空指针,所以输出了错误信息,由于p指针是由FindCmd函数返回的,我们接着查看FindCmd函数。

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

       很明显,我们需要继续查看SearchLinkTableNode函数,在linktable.c文件中找到SearchLinkTableNode函数,我们来继续检查

#int Conditon(tLinkTableNode * pNode)调用了回调函数
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; }

     分析了以上代码可以发现,输入quit命名返回错误信息是因为SearchLinkTableNode函数返回了NULL指针,很明显返回NULL指针只有在pLinkTable和Conditon至少有一个为NULL或者直到pNode循环遍历结束以后也未满足Conditon(pNode) == SUCCESS的条件,很显然前者我们可以排除,我们来分析后者的情况。

     首先我们要知道pLinkTable->pTail是什么

#LinkTable的数据结构
typedef struct LinkTable { tLinkTableNode *pHead; tLinkTableNode *pTail; int SumOfNode; pthread_mutex_t mutex; }tLinkTable;
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;
    }
#由此可知pTail指向的是最后一个节点 else { pLinkTable->pTail->pNext = pNode; pLinkTable->pTail = pNode; } pLinkTable->SumOfNode += 1 ; pthread_mutex_unlock(&(pLinkTable->mutex)); return SUCCESS; }

       通过分析以上的代码,我们很容易发现,当pNode遍历到最后一个指针是,并未判断Conditon(pNode) == SUCCESS是否成了,

而是直接返回了NULL指针,因此将while循环的条件改为pNode!=NULL,修改以后我们在测试一下,重新编译运行。发现已经解决了bug。

       

 三、callback接口

1.何为callback

      通俗的说就是通过函数指针调用的函数,定义如下:

      如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

2.实现机制:

       1.定义一个回调函数;
       2.提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;

       3. 当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

3.回调函数的好处

        1.使得程序设计更加灵活。

        2.当我们想通过一个统一接口实现不同内容的时候,用回调函数来实现就非常合适。

        3.任何时候,如果你所编写的函数必须能够在不同的时刻执行不同的类型的工作或者执行只能由函数调用者定义的工作,你都

可以用回调函数来实现。

        4.使用此函数可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被

调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以

灵活的使用不同的方法。

标签:pTail,函数,callback,编程,pNode,pLinkTable,工程化,NULL,指针
来源: https://www.cnblogs.com/ustc-kunkun/p/12499964.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有