您的位置 首页 java

这篇文章足以让你彻底明白C语言回调函数是怎么回事

当说到 回调函数 ,我先打个比方,在很多场景中,某个客户,拿着游戏项目想找某些游戏开发商合作,前提不知道他们的实力如何,先投石问路,然后在每家公司叫他们做好结构功能等设计,符合要求的我再投谁。对客户来说,我要的是先看看你们给我们写的代码是否有可维护性,可读性,可扩展性,灵活性,简洁性,可复用性,可测试性甚至是健全性等问题的慎重考虑。面对这些要求对开发商而言技术实力就显得更重要,写出符合客户要求的,在代码上,回调函数有时起着很关键性的作用。

回调函数的作用:

回调函数在程序开发中是一个非常重要的概念,所谓的 回调 其实就是不同程序模块之间的接口和约定,是软件分层设计的基本方式。只要是回调函数的使用可以在很大程度上提升编程的效率,所以很多场景开发中,有一些需求是必须要使用回调函数来实现的。同时,在C语言中,回调函数只能使用函数指针来实现,比如C++等语言还可以使用 仿函数 或匿名函数。

什么是回调函数?

在此我引用网络上的一段话,更加能通俗易懂:

回调函数是一种非常重要的机制,主要可以用来实现软件的分层设计,使得不同软件模块的开发者的工作进度可以独立出来,不受时空的限制,当需要的时候只需要通过约定好的接口(或者标准)相互契合在一起,也就是C++或者 JAVA 等现代 编程语言 声称的所谓面向接口编程。同时回调也是定制化软件的基石,通过回调机制将软件的前端和后端分离,前端提供逻辑策略,后端提供逻辑实现。

我们知道C语言中的函数实际上就相当于一个人,你给他一些参数,他帮你完成一样固定的功能,用厨师和医生比喻下:“比方我给厨师一道菜名,厨师就会把这道菜烹饪出来;你带一位病人给医生看,医生将会对这位病人进行医治等等。这里,厨师和医生都相当于功能确切的函数,等着你来调用它。

我们身边不乏有很多这样的“函数”,假设你每天都到食堂吃饭,发现每次去吃饭都要走很长的一段路程,会比较累,于是你就想让公司的前台同事去吃饭时顺便帮你打一盒饭回来。那么,在同事外出午餐之前,你就等于传递一些参数给你的同事(比方说:20块钱,以及说清楚你要吃什么,蛋炒饭还是西红柿炒饭等等),到半个小时后,这位同事经过了付款等操作后拿着热腾腾的盒饭回来给你了。这一系列的过程就是普通函数的调用过程。而你相当于调用了你的同事,实现了不用跑远路光坐着也能吃上饭的美好夙愿,这个过程就像下面一张图所示一样:

当然这还不够,还有下续:

毕竟每个人老是吃一家食堂的饭也是会腻的吧,最后导致你已经确定你无法再吃下去了,于是乎就决定不再吃食堂的饭了,改为自己做饭。这个做饭不能全由一个人来做,否则谈论这个回调就没啥意义了。所以还是继续要去调用前台同事帮我干活(似乎有劳累同事的感觉),老是叫人做事也怪不好意思的,所以叫人干活多少给点钱人家这还算过意得去。

把自己想吃的东西,让这位同事帮你去菜市场买回来,然后给做好,再端给你吃(似乎像保姆了,仅比喻~~)。虽然这位同事看起来非常愿意为你效劳的,愿意为你跑腿、买菜、砍价、端茶递水,到最后发现居然是一个不会做饭的人。在无奈之下,不麻烦同事了。有钱任性的你于是雇佣了一名资深大厨,啥也不会只会做饭的就行,你只要给他材料就行了。

就这样,啰嗦了一大堆,午饭做饭的过程:你将要吃的菜品清单和需要花的钱只传递给你的同事,甚至你还把大厨的电话号码给到同事那里,告诉他说:买了菜之后就打这个电话,让大厨帮你把菜做好了再给我送过来OK。与此同时,你可以“定制”你的大厨,你叮嘱你的大厨说:大厨,我喜欢重口味的还是清淡的,以后你做的任何菜里,都要放够足量的辣椒酱油盐还是少放清淡为止。就像如下图所示一样:

在上面为了吃个不易的午饭,也实现了典型的回调机制,你定制了一位大厨,然后你在调用同事的同时,也把大厨的电话号码也给到你同事,所以同事在需要做饭的时候,就会根据你提供的参数(大厨的电话)回过去调用(回调)那位大厨,把做好的饭菜端给你。

在上图中有一个最重要的信息就是:左边的两个人和右边的那个人之间有一条饱含深意的虚线,他意味着左右两边是两拨人,左边的人负责做饭和吃饭,右边的人负责跑腿、砍价等。比如:你只要知道怎么找到你的同事,传递给他参数让他干活就行了,根本不需要知道同事买的菜是从哪里买的,不管路程远还是近,另外也管好这位大厨,让他只做符合我口味好吃的饭菜就行,也根本不需要管买菜的同事什么时候会找大厨,甚至不管他们以后感情发展如何。对于右边的同事而言,他只要根据你的嘱咐去跑腿,在有必要的时候“回调”一下大厨就行,也根本不需要管大厨做的饭菜好不好吃,因为是做给我吃,口味由我决定。

所以上面图中左右两拨人就各司其职,互不耦合,独立性强,但又可以非常方便地相互合作,达成共识,能完成一个丰富的功能。这里,大厨就是一个回调函数——一个不被设计者(你自己)直接调用,而是被其他人(你的同事)回过来调用的函数。你传递给同事的电话号码,相当于一个能找到大厨的指针,被称之为” 函数指针 “,回调机制就是靠传递函数指针来告知回调函数的位置的。

回调函数怎么写?

啰嗦了一堆,总算理解了什么是回调函数,现在看下简单的回调函数应该如何实现,就以代码形式演示利用回调函数查找数组中的元素是如何来实现的?如下所示:

 #define _CRT_SECURE_NO_WARNINGS
# include  <stdio.h>
#include <string.h>
#include <stdlib.h>

// 创建 结构体 
 struct  arrInfo
{
 char  name[64];
int age;
};

// 底层函数的实现
int printArr( void  * arr, int elesize, int len, void * date, int(*arrCompare)(void *, void *))
{
char * p = arr;
for (int i = 0; i < len; i++) {
// 获取到每个元素的首地址
char * arrAddr = p + elesize * i;
// 如果用户输入的数据 == 数组中遍历的元素
if (arrCompare(date, arrAddr)) {
return 1;
}
}
return 0;
}

// 用户自己所提供的函数
int myConfig(void * d1, void * d2)
{
struct arrInfo * p1 = d1;
struct arrInfo * p2 = d2;
if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age) {
return 1;
}
else {
return 0;
}
}

void test()
{
//查找数组中是否有指定类型的元素,如果有返回1,如果没有则返回0
struct arrInfo arr[] =
{
{ "Hello", 111 },
{ "World", 222 },
{ "Love", 333 },
{ "Chinese", 444 }
};
int len = sizeof(arr) / sizeof(struct arrInfo);
struct arrInfo p = { "World", 222};
int res = printArr(arr, sizeof(struct arrInfo),  len , &p, myConfig);
if (res) {
 printf ("找到数组中的元素n");
}
else {
printf("未找到数组中的元素n");
}
}

int main() {
test();
return 0;
}  

结果是找到此数组元素的,如下图所示:

文章来源:智云一二三科技

文章标题:这篇文章足以让你彻底明白C语言回调函数是怎么回事

文章地址:https://www.zhihuclub.com/176199.shtml

关于作者: 智云科技

热门文章

网站地图