函数指针与指针函数
先来看两种声明:
int* fun(int i);
int (*fun)(int i);
首先明确,前者为指针函数,后者为函数指针,他们的区别就在于:
- 一个返回值类型为int型指针的函数
- 一个指向返回值类型为int的函数的指针
也就是说函数指针可以将函数变成一个类似与变量的东西供我们操作
两者的用法实例:
1.
#include<stdio.h>
#include<stdlib.h>
int* fun(int i)
{
return ((int*)malloc(i));
/*
申请一块动态内存,以指针的形式返回,等价于
int* p = (int*)malloc(i);
return p;
*/
}
int main(int argc,char* argv[])
{
int* p = fun(sizeof(int));
*p = 1;
printf("%d",*p);
free(p);
return 0;
}
指针函数可以将一个指针变量作为返回值
#include<stdio.h>
#include<stdlib.h>
int fun(int i)
{
printf("num %d",i);
return 0;
}
int main(int argc,char* argv[])
{
//这里也可以将参数部分的变量名写上去,没有什么区别int (*pfun)(int i) = fun;
int (*pfun)(int) = fun;
pfun(2); //这里调用的是函数指针pfun,不是函数fun
return 0;
}
函数指针可以将一个函数地址存入指针,之后通过调用该指针来达到调用函数的目的
异步回调机制
什么是回调?对于对windows编程与js比较了解的同鞋肯定都知道,但为了照顾不了解的同鞋,我还是来简单介绍一下.
从函数的调用方式来讲,可以分为三类:同步调用、回调、异步调用。
同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;
回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。
同步调用是三者当中最简单的,而回调又常常是异步调用的基础
通常我们直接的去调用函数算是一种同步调用,同步调用最大的特点,我个人认为就是你的函数去主动的调用其他函数. 而异步回调机制恰恰相反, 它是你的函数被动的被其他函数所调用
函数指针的作用
说完以上部分,就再来距举例说明一下函数指针的作用
假想场景:
假设你在项目中负责编写一个函数A, 这个函数B的功能是:
- 循环检查, 每一分钟检查一次进程1是否还在运行,
- 将进程1的运行状态通过参数传递给另一个函数
- 将状态写入日志文件
以上场景 , 可能会存在多个解决方法, 但这里就利用异步回调的方式来解决一下这个问题
伪代码:
//将函数指针以函数参数的形式进行传递
void A(void (*fun)(int status))
{
while(1)
{
//获取进程1的状态代码......
fun(以整数形式代表的进程1的状态);
Sleep(1000*60);
//写入日志文件
}
}
不同程序员编写的调用函数A的函数:
程序员a:
void callback(int status)
{
if(status)
//如果发现进程1正在运行, 那就向服务端A发送一条消息
}
int getStatus()
{
A(callback);
return 0;
}
程序员b:
void oneProcess(int status)
{
if(status)
//如果发现进程1没有在运行,那就创建进程1
}
int checkProcess()
{
A(oneProcess);
return 0;
}
因为我们的函数会不停的去循环检查,所以无法通过返回值的形式来向调用者反馈进程1的状态, 在加上可能会有多个不同的函数利用我们的函数来获取进程1的状态来进行不同的操作
除此之外,接触过socket编程的同学肯定知道, 服务端在listen后会将accept放置在一个死循环里用于接受客户端的套接字, 假如说我们正在封装一个TCP通信库, 想要把accept接受到的客户端套接字通过返回值的形式传递给第三方调用者明显是不现实的, 但是如果利用了回调机制,那就会变得很容易.