工程化编程实战callback接口学习笔记(作业二)

1. 在VSCode下编译运行lab5-1

编译代码

ERROR原因:menu.c中缺少了string类库,无法使用strcmp
解决ERROR:menu.c中include <string.h>导入类库后,再进行编译

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

使用help打印出所有的command,可以看出只有helpquit,挨个测试功能后发现quit不能按照期望输出

step-2.1 排查错误原因(手工调试和使用GDB工具)

step-2.2 手工法排查:

排查错误过程:
可以看到,输出This is a wrong cmd!是因为p是空指针,原因是FindCmd函数返回为空,查看FindCmd函数内容:

FindCmd函数只有一个尾调用,执行SearchLinkTableNode(head,SearchCondition)函数,SearchLinkTableNode代码如下:

可以看到,Conditon函数是一个回调函数。详解参考这篇文章。SearchLinkTableNode是call-in方式函数,其中有一个函数作为参数,这个作为参数的函数就是callback函数,即代码中Conditon函数。回调函数的实现方式及优点见文末。

可以看到,SearchLinkTableNode为空的可能有:
1.链表为空
2.链表遍历完成后没有找到对应的command node
由于help命令是可以正常运行的,所以只可能是quit对应的node没有正常被遍历,通过下图对添加cmmand节点的过程进行分析出


quit node是添加在链表结尾的,每次添加新node时会把pNext置null,而SearchLinkTableNode函数中遍历链表时的条件为pNode != pLinkTable->pTail,显然没有判断到最后一个节点。所以,只需要把判断条件改为pNode != null后,重新编译运行,即可得到正确结果。

step-2.3 使用GDB工具排查(过程已通过注释列出):

xxx@xxx-virtual-machine:~/桌面/lab5-1/lab5.1$ gdb -q se2020
Reading symbols from se2020...done.
(gdb) list                                                             //列出menu.c中的内容
89	    pNode->cmd = "quit";
90	    pNode->desc = "Quit from Menu Program V1.0";
91	    pNode->handler = Quit; 
92	    AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);
93	 
94	    return 0; 
95	}
96	
97	/* menu program */
98	
(gdb) 
99	tLinkTable * head = NULL;
100	
101	int main()
102	{
103	    InitMenuData(&head); 
104	   /* cmd line begins */
105	    while(1)
106	    {
107	        printf("Input a cmd number > ");
108	        scanf("%s", cmd);
(gdb) 
109	        tDataNode *p = FindCmd(head, cmd);
110	        if( p == NULL)
111	        {
112	            printf("This is a wrong cmd!
 ");
113	            continue;
114	        }
115	        printf("%s - %s
", p->cmd, p->desc); 
116	        if(p->handler != NULL) 
117	        { 
118	            p->handler();
(gdb) break 109												    //对109行的FindCmd函数加断点
Breakpoint 1 at 0x400dea: file menu.c, line 109.
(gdb) run													    //打完断点运行程序
Starting program: /home/dfx/桌面/lab5-1/lab5.1/se2020 
Input a cmd number > quit										//输入quit指令

Breakpoint 1, main () at menu.c:109
109	        tDataNode *p = FindCmd(head, cmd);
(gdb) s														    //使用s进入FindCmd函数
FindCmd (head=0x603010, cmd=0x6020a0 <cmd> "quit") at menu.c:60
60	    return  (tDataNode*)SearchLinkTableNode(head,SearchCondition);
(gdb) s												     //使用s进入SearchLinkTableNode函数
SearchLinkTableNode (pLinkTable=0x603010, Conditon=0x400bf3 <SearchCondition>)
    at linktable.c:144
144	    if(pLinkTable == NULL || Conditon == NULL)
(gdb) n																//n为单行调式
148	    tLinkTableNode * pNode = pLinkTable->pHead;
(gdb) n
149	    while(pNode != pLinkTable->pTail)
(gdb) n
151	        if(Conditon(pNode) == SUCCESS)
(gdb) n
155	        pNode = pNode->pNext;
(gdb) n
149	    while(pNode != pLinkTable->pTail)
(gdb) n
151	        if(Conditon(pNode) == SUCCESS)
(gdb) n
155	        pNode = pNode->pNext;
(gdb) n
149	    while(pNode != pLinkTable->pTail)
(gdb) n	  //第三次while循环执行结束,由手工法也可以知道,初始化一共有三个节点,所以quit node没有被遍历
157	    return NULL;
(gdb) n
158	}
(gdb) n
FindCmd (head=0x603010, cmd=0x6020a0 <cmd> "quit") at menu.c:61    //FindCmd返回
61	}
(gdb) n
main () at menu.c:110
110	        if( p == NULL)											//判断的quit cmd为null
(gdb) n
112	            printf("This is a wrong cmd!
 ");
(gdb) n
This is a wrong cmd!
113	            continue;
(gdb) 

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

Definition:回调函数是异步执行或稍后执行的函数。其是通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数
Example:有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。
Advantage:回调机制提供了非常大的灵活性,在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。
设计方法:回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。比如java回调机制:
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。

  • 同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;
  • 回 调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
  • 异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。

参考自

原文地址:https://www.cnblogs.com/fxding/p/12503111.html