函数调用是一个比较容易理解的概念,即使是刚开始学习的朋友也可以理解函数调用的实现方式。函数调用就是通过调用一个已经封装好的函数来实现某个特定的功能。
在函数调用中,可以将一个或多个功能通过函数的方式进行封装,对外只提供一个简单的函数接口,然后在其他地方进行调用。
函数调用的方式
函数调用难道还有其他的方式吗?不是直接封装好然后调用吗???
实际上,函数调用有两种方式:直接调用和间接调用。
直接调用
直接调用是我们平常使用的方式,下面的示例就是直接调用的方式之一。
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;
}
什么场景使用
函数指针在软件架构分层设计中十分重要,因为分层设计中有一个设计原则,那就是下层函数不能直接调用上层函数,那么可以通过函数指针的方式实现;一般称上层通过函数指针赋值给下层的函数为回调函数。
什么情况会存在需要下层程序需要调用上层程序的呢?
比如串口数据接收,虽然可以通过查询的方式接收,但是远不及通过串口中断的方式接收及时,当接收完成时,需要立即通知上层读取数据进行处理,而不是等待上层程序查询读取。
如何实现呢?
比如硬件抽象层/驱动层中的串口模块实现函数
/************* 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();
}
}
}
上述示例中通过函数指针的方式间接调用了应用层的函数,而且并不违背分层设计原则。
如果看代码不能立即理解的话,可以尝试通过下图理解:
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !