1、前言函数调用很好理解,即使刚学没多久的朋友也知道函数调用是怎么实现的,即调用一个已经封装好的函数,实现某个特定的功能。
把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口,然后在其他地方调用即可
2、函数调用方式函数调用难道还能怎么调用?不就封装好直接调用吗???
函数调用方式分为两种:直接调用和间接调用
直接调用
直接调用就是我们平常使用的方式,下面的方式就属于直接调用了。
int sumfun(int a, int b){ return a + b;}int main(){ // 直接调用定义好的函数 int sum = sumfun(5, 6); printf(sum=%d, sum); return 0;}间接调用
间接调用在初学时很难使用到,这是通过函数指针的方式实现的。
函数指针本质是一个指针变量,是一个指向函数的指针(函数本身也是有地址的,指向的是函数入口);
而指针函数本质是一个函数,其返回值为指针。
函数指针的用法如下:
typedef int (*functioncb)(int, int);int sumfun(int a, int b){ return a + b;}int main(){ // 将定义好的函数赋值给函数指针 functioncb pfnsum = sumfun; // 通过函数指针间接调用 int sum = pfnsum(5, 6); printf(sum=%d, sum); return 0;}3、什么场景使用函数指针在软件架构分层设计中十分重要,因为分层设计中有一个设计原则,那就是下层函数不能直接调用上层函数,那么可以通过函数指针的方式实现;一般称上层通过函数指针赋值给下层的函数为回调函数。
什么情况会存在需要下层程序需要调用上层程序的呢?
比如串口数据接收,虽然可以通过查询的方式接收,但是远不及通过串口中断的方式接收及时,当接收完成时,需要立即通知上层读取数据进行处理,而不是等待上层程序查询读取。
如何实现呢?
比如硬件抽象层/驱动层中的串口模块实现函数
/************* uart.c 文件 ****************/static uartrecvcb sg_pfnuartrecv;// 设置数据帧接收处理回调函数void uart_setrecvcallback(uartrecvcb pfnuartrecv){ sg_pfnuartrecv = pfnuartrecv;}void uart_task(void){ if (recvend) { // 数据一帧接收完成立即调用 if (sg_pfnuartrecv != null) { sg_pfnuartrecv(uartrecvbuf, uartrecvlength); } }}/************* uart.h 文件 ****************/typedef void (*uartrecvcb)(const char *, int);extern void uart_setrecvcallback(uartrecvcb pfnuartrecv);extern void uart_task(void);应用层代码中实现回调函数,并调用下层函数。
// 回调函数:串口数据处理void onuartrecvprocess(const char *pbuf, int length){ // 处理串口数据 printf(recv: %s, pbuf);}int main(){ uart_setrecvcallback(onuartrecvprocess); while(1) { if (timeflag) { uart_task(); } }}上述示例中通过函数指针的方式间接调用了应用层的函数,而且并不违背分层设计原则。
如果看代码不能立即理解的话,可以尝试通过下图理解:
如何选购一款性价比极高的超极本
Web Bluetooth可以应用在哪些方面
3D打印机有啥缺点
盘点那些常用的Linux性能分析工具2
回顾2020年印度手机产业链的发展状况
嵌入式软件架构设计之函数调用
电销机器人的工作流程是怎样的
高速PCB设计中的时序分析以及仿真策略
适用于多标准收发器中的可重构流水线ADC的应用设计
微软在苏格兰部署的海底数据中心正式开始运行
量子计算能做什么?谷歌和微软竞赛白热化
如何对带有ATMEGA644P或1284P的Arduino板进行DIY
NVIDIA股票大跌25% 未来GPU前景依然看好
电源适配器自动综合测试系统
学习下如何去抓APP的数据
佳能EOSM6评测 总体来讲特色非常鲜明
GitHub访问速度慢怎么办?教你一招解决!
主流A/D转换芯片学习详解(1):美信MAX197
三星天翼3G旗舰W799评测
关于世界顶尖锂电池研究团队及研究方向的介绍