ICode9

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

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

2020-03-19 21:56:13  阅读:251  来源: 互联网

标签:编程 函数 callback tDataNode cmd pNode SearchLinkTableNode 工程化 tLinkTableNode


实验环境

本次实验的环境是Windows 10+VS Code,实验用到的代码先在Linux环境下解压再拷贝到Windows中。

 

编译、运行

 先进入代码所在目录,然后输入指令“gcc -o test linktable.c menu.c”得到可执行文件“test.exe”

可以看到,我们的目录下生成了可执行文件。

运行“test.exe”,并键入“quit”

跟预期的一样,quit指令不能得到正确的响应。

 

纠错

查看menu.c的main函数可以发现,当指针p为空时,会显示“This is a wrong cmd!”,所以显然给p赋值的FindCmd函数返回值为空。

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函数,其具体内容如下:

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

该函数直接返回SearchLinkTableNode函数的调用结果,看来问题出在了SearchLinkTableNode上。

再查看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;
}

观察代码,首先我们可以发现,当pLinkTable或Condition为空时,返回值为空。但是不幸的是我们遇到的不是这种情况。再往下看,我们可以发现,当遍历到pLinkTable的尾结点时,也直接返回空,而没有对尾结点的Condition值进行判断。而巧合的是,由InitMenuData函数我们可以看到,指令“quit”所在的节点恰好是链表的尾结点,所以就会出现不能正常相应“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接口运行机制与设计方法

通常函数的参数是一些变量,比如menu.c中的FindCmd函数:tDataNode* FindCmd(tLinkTable * head, char * cmd);

但是有一些函数的参数中可能也有函数,如linktable.c中的SearchLinkTableNode函数:tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode));其有一个参数是函数int Conditon(tLinkTableNode * pNode),这个作为参数的Condition函数即为callback函数。callback函数的运行机制,以SearchLinkTableNode函数为例,只有在其中出现调用Condition函数的语句时才会调用Condition函数,也就是SearchLinkTableNode函数中的这一句——“if(Conditon(pNode) == SUCCESS)”。也就是说,Condition函数作为参数并不是一开始就传入的。callback函数设计方法无外乎定义callback函数,并使其成为另一个函数的参数。

callback函数的作用在我看来主要是对主调函数隐藏了其实现细节,且可以与主调函数分开编写。即主调函数需要某个功能的支撑,可以先用一个callback函数作为参数,callback函数具体的实现可以稍后再来完成。有点类似于C++中的类的public成员函数。

标签:编程,函数,callback,tDataNode,cmd,pNode,SearchLinkTableNode,工程化,tLinkTableNode
来源: https://www.cnblogs.com/sfnevermore/p/12527451.html

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

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

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

ICode9版权所有