funcPointer, callBack and depedencies

Funcpointer and Callback
This article mainly talk about the using of the function pointer and the call back function in c/c++.

fuction pointer

what is the type of the func?

int(*)(char a)

first part “int” means the return value of the function is the type of int, the second part “*” means this is a function pointer, the third part “char a” means that the input parameter of the function is a char character.

function pointer declaration:

returntype (* functionptrname)(arguments...)

function pointer 指向函数的首地址,也就是指向一段可以执行的代码的首地址,但是并非仅仅如此,因为还要和输入参数以及返回参数相关联。

下面的例子是一个基本的function pointer的定义以及使用:

#include "stdio.h"
int func(char a)
{
printf("%d\n", a);
return 0;
}
int main()
{
int (*funcptr)(char a);
funcptr = func;
funcptr('a');
return 0;
}

可以看到从函数名称调用和从指针调用效果是一致的。这里的函数指针是可以指向函数所在地址的指针,但并不是任何函数都可以,必须要是形参为char a 并且返回值为int的函数才行。如果将上面的指针指向一个其他类型的指针就会有如下的错误:

#include "stdio.h"
int funca(char a)
{
printf("%d\n", a);
return 0;
}
int funcb(int a)
{
printf("test charb\n");
return 0;
}
int main()
{
int (*funcptr)(char a);
funcptr = funca;
funcptr('a');
funcptr = funcb;
return 0;
}
./funcp.c:22:13: warning: incompatible pointer types assigning to 'int (*)(char)' from 'int (int)'
[-Wincompatible-pointer-types]
funcptr = funcb;
^ ~~~~~
1 warning generated.

那么这样做和直接调用函数相比的好处在什么地方?和直接通过函数名称调用excutable code segmentation相比的好处在哪里。

callback

在基于event的编程模式中,call back会被经常使用到。总的来说分为两部分,函数注册+函数调用。在programming的时候先把函数的地址注册进某个framework中,之后framework在运行的时候,当某些事件被触发了之后就调用这个对应的注册进来的函数。本质上来讲,callback就是先将函数的地址传递进某个地方,再等到未来合适的某个时机调用这个函数。

下面这个例子是callback的一个使用

typedef int (*JobCompleteCallBack)(char a);

int func(char a)
{
printf("job complete, input parameter %c\n", a);
return 0;
}
void LongJob(char job, JobCompleteCallBack jobfunc)
{
printf("do the long running job %c\n", job);
jobfunc('b');
}
int main()
{
LongJob('a', func);
return 0;
}

可以看到,这里首先使用typedef重新定义了函数指针从而增强了代码的可读性,在LongJob函数的时候,其中的一个形参数是函数指针,在某些逻辑执行完成之后会调用这个callback函数。需要注意的是对于callback的代码一定要按照callback的场景来理解,问自己,这个背后的逻辑是想说”在某个条件触发的时候就执行某个函数”,这个时候一定要跳出来整体看,要是盯着代码一行一行地往下走就容易把自己弄晕。

在实际的case中,常常通过function table的形式只用callback。function table的key值是具体的event类型,value值是具体的预先注册好的function table,两者对应起来就可以通过某些具体的event来触发对应的函数了。这个时候再调用函数就叫callback。这种通过事件来触发函数的机制可以理解为event-driven trigger。

下面的例子中使用array数组来模拟一个简单的call back function table,实际上使用map会有更高的效率。下面的例子就是通过标准输入来触发不同的函数,这就是大部分event-driven programming paradigm的原型。

#include "stdio.h"
typedef void (*eventFunc)();
struct MYSTRUCT
{
int eventTypeLast;
eventFunc funcTable[3];
} myGlobalStruct;
void func0()
{
printf("triggured by event 0\n");
}
void func1()
{
printf("triggured by event 1\n");
}
void func2()
{
printf("triggured by event 2\n");
}
void Init()
{
myGlobalStruct.funcTable[0] = func0;
myGlobalStruct.funcTable[1] = func1;
myGlobalStruct.funcTable[2] = func2;
}
int main()
{
Init();
int eventNow;
while (1)
{
scanf("%d", &eventNow);
if (eventNow >= 0 && eventNow < 3)
{
myGlobalStruct.eventTypeLast = eventNow;
myGlobalStruct.funcTable[eventNow]();
}else{
break;
}
}
return 0;
}

depedencies

Another important property for the function pointer is to avoid the extra depedencies, and it is a basic strategy to implement the factory method by this way. For example, we want to use different lower level networking or rpc layer. The function pointer can be used to decouple these two components. This is an exmaple in our project recently. we plan to use another communicator without modifying the original build files a lot, so we provide a patch to create the upper level class instead of using the particular create function from the lower layer. If the lower level layer includes a lot of particular libraries and we do not necessary includes these libraries into the upper level, the possible option is to let all the lower level to implement a create function, and the return value can be a void* or super class. At the upper level, it just need to get the function pointer and call the specific factory function based on dedicated function name. It is ok to support the lower layer in decoupled way. We do not modify the build file at the upper level back and forth by this way.

reference

https://www.youtube.com/watch?v=47m7yhaKhgM

推荐文章