这次来记录下对于函数指针的理解
函数指针其实就是个指针,而指针就是一个变量而已。
首先来看常见的函数指针
uint8_t(*func_ptr)(uint8_t,uint8_t);
func_ptr一个函数指针
如何使用?
将func_ptr指向一个函数,然后调用指针func_(uint8_t,uint8_t)就行
例如
uint8_t a=10;
uint8_t b=20;
uint8_t Sum(uint8_t x,uint8_t y)
{
return x + y;
}
func_ptr = Sum;
func_ptr(a,b);
当使用func_ptr(a,b)时,实际运行的是Sum(a,b)
还有一种写法
typedef uint8_t(*func_ptr)(uint8_t,uint8_t)
这个意思是要定义的类型是uint8_t (*)(uint8_t,uint8_t) 别名是func_ptr
例如
typedef uint8_t(*func_ptr)(uint8_t,uint8_t) //定义一个函数指针
func_ptr pFun; //声明了一个函数指针
pFun = Sum;
pFun(a,b); //实际运行的会是Sum(a,b)
函数指针也比较常见的结构体中
参考安富莱的串口的结构体
/* 串口设备结构体 */
typedef struct
{
USART_TypeDef *uart; /* STM32内部串口设备指针 */
uint8_t *pTxBuf; /* 发送缓冲区 */
uint8_t *pRxBuf; /* 接收缓冲区 */
uint16_t usTxBufSize; /* 发送缓冲区大小 */
uint16_t usRxBufSize; /* 接收缓冲区大小 */
__IO uint16_t usTxWrite; /* 发送缓冲区写指针 */
__IO uint16_t usTxRead; /* 发送缓冲区读指针 */
__IO uint16_t usTxCount; /* 等待发送的数据个数 */
__IO uint16_t usRxWrite; /* 接收缓冲区写指针 */
__IO uint16_t usRxRead; /* 接收缓冲区读指针 */
__IO uint16_t usRxCount; /* 还未读取的新数据个数 */
void (*SendBefor)(void); /* 开始发送之前的回调函数指针(主要用于RS485切换到发送模式) */
void (*SendOver)(void); /* 发送完毕的回调函数指针(主要用于RS485将发送模式切换为接收模式) */
void (*ReciveNew)(uint8_t _byte); /* 串口收到数据的回调函数指针 */
uint8_t Sending; /* 正在发送中 */
}UART_T;
static UART_T g_tUart1;
当要使用结构体的函数指针时,首先先让指针指向函数
g_tUart3.SendBefor = RS485_SendBefor; /* 发送数据前的回调函数 */
之后就可以正常使用函数指针
if (g_tUart1.SendBefor != 0)
{
g_tUart1.SendBefor(); /* 如果是RS485通信,可以在这个函数中将RS485设置为发送模式 */
}
使用结构体里面的函数指针好处是可以将同一个功能的东西封装在一个模块中
回调函数
函数指针作为函数的形参我们把这个函数指针就叫做回调函数
例如
uint8_t compute_func(uint8_t (*func_ptr)(uint8_t, uint8_t),uint8_t, uint8_t);
在stm32的HAL库中,是使用了大量的回调函数的,回调机制可以更好地分离代码,应用层和驱动层完全分离。