函数指针
优质
小牛编辑
147浏览
2023-12-01
函数指针基础语法
函数指针用于指向一个函数,函数名是函数体的入口地址。函数指针可以实现面向对象编程,可以实现软件分层设计(回调函数)。
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//数组指针 语法 梳理
//定义一个数组类型
//int a[10];
//定义一个指针数组类型
//定义一个指向数组类型的指针,数组类的指针
void main01()
{
int a[10]; //a代表的是数组首元素的地址 &a代表整个数组的地址 a+1 4 &a+1步长 40
{
//定义一个数组类型
typedef int (myTypeArray)[10];
myTypeArray myArray;
myArray[0] = 10;
printf("%d \n", myArray[0]);
}
{
//定义一个数组指针类型
typedef int (*PTypeArray)[10]; //int *p
PTypeArray myPArray; //sizeof(int) *10
myPArray = &a;
//int b = 10;
//int *p = NULL;
//p = &b;
(*myPArray)[0] = 20;
printf("a[0]: %d \n", a[0]);
}
{
//定义一个指向数组类型的指针,数组类的指针
int (*MyPointer)[10]; //变量 告诉C编译器 给我分配内存
MyPointer = &a;
(*MyPointer)[0] = 40;
printf("a[0]: %d \n", a[0]);
}
system("pause");
return ;
}
//函数指针语法梳理
//1 如何定义一个函数类型
//2 如何定义一个函数指针类型
//3 如何定义一个 函数指针 (指向一个函数的入口地址)
int add(int a, int b)
{
printf("func add ....\n");
return a +b;
}
void main02()
{
add(1, 2); //直接调用调用,函数名就是函数的入口地址
//定义一个函数类型
{
typedef int (MyFuncType)(int a, int b); //定义了一个类型
MyFuncType *myPointerFunc = NULL; //定义了一个指针, 指向某一种类的函数
myPointerFunc = &add; //细节
myPointerFunc(3, 4); //间接调用
myPointerFunc = add; //细节,C 过程 兼容历史版本的原因
myPointerFunc(3, 4); //间接调用
}
//定义一个函数指针类型
{
typedef int (*MyPointerFuncType)(int a, int b); //int * a = NULL;
MyPointerFuncType myPonterFunc; //定义一个指针
myPonterFunc = add;
myPonterFunc(5, 6);
}
//函数指针
{
int (*MyPonterFunc)(int a, int b); //定义了一个变量
MyPonterFunc = add;
MyPonterFunc(7, 8);
}
system("pause");
}
函数指针做函数参数
当函数指针作为函数的参数,传递给一个被调用函数,被调用函数就可以通过这个指针调用外部的函数,这就形成了回调
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int myadd(int a, int b) //子任务的实现者
{
printf("func add() do...\n");
return a + b;
}
int myadd2(int a, int b) //子任务的实现者
{
printf("func add2() do...\n");
return a + b;
}
int myadd3(int a, int b) //子任务的实现者
{
printf("func add3() do...\n");
return a + b;
}
int myadd4(int a, int b) //子任务的实现者
{
printf("func add4() do...\n");
return a + b;
}
//定义了一个类型
typedef int (*MyTypeFuncAdd)(int a, int b);
//函数指针做函数参数
int MainOp(MyTypeFuncAdd myFuncAdd)
{
int c = myFuncAdd(5, 6);
return c;
}
// int (*MyPointerFuncAdd)(int a, int b)
int MainOp2(int (*MyPointerFuncAdd)(int a, int b) )
{
int c = MyPointerFuncAdd(5, 6); //间接调用
return c;
}
//间接调用
//任务的调用和任务的编写可以分开
void main()
{
/*
MyTypeFuncAdd myFuncAdd = NULL;
myadd(1, 2); //直接调用
myFuncAdd = myadd;
myFuncAdd(3, 4); //间接调用
MainOp2(myadd);
MainOp(myadd);
*/
//在mainop框架 没有发生任何变化的情况下
MainOp(myadd2);
MainOp(myadd3);
MainOp(myadd4);
system("pause");
return ;
}
回调函数:函数的调用和函数的实现 有效的分离
回调函数的本质:提前做了一个协议的约定(把函数的参数、函数返回值提前约定)
请思考:C编译器通过那个具体的语法,实现解耦合的?
C++编译器通过多态的机制(提前布局vptr指针和虚函数表,找虚函数入口地址来实现)
回调函数
回调函数:利用函数指针做函数参数,实现的一种调用机制,具体任务的实现者,可以不知道什么时候被调用。
回调机制原理:
- 当具体事件发生时,调用者通过函数指针调用具体函数
- 回调机制的将调用者和被调函数分开,两者互不依赖
- 任务的实现 和 任务的调用 可以耦合 (提前进行接口的封装和设计)
函数指针正向调用
函数指针做函数参数,被调用函数和主调函数不在同一个文件中、模块中。
//函数指针类型
//客户端初始化 获取handle上下文
typedef int (*CltSocketInit)(void **handle /*out*/);
//客户端发报文
typedef int (*CltSocketSend)(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/);
//客户端收报文
typedef int (*CltSocketRev)(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/);
//客户端释放资源
typedef int (*CltSocketDestory)(void *handle/*in*/);
void C函数指针正向调用Dlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
AfxMessageBox("ddddd");
HINSTANCE hInstance;
//用函数指针类型定义函数指针变量
CltSocketInit cltSocketInit;
CltSocketSend cltSocketSend;
CltSocketRev cltSocketRev;
CltSocketDestory cltSocketDestory;
//找函数的入口地址
hInstance=::LoadLibrary("c:/socketclient.dll");
cltSocketInit =(CltSocketInit)::GetProcAddress(hInstance, "cltSocketInit");
cltSocketSend =(CltSocketSend)::GetProcAddress(hInstance, "cltSocketSend");
cltSocketRev =(CltSocketRev)::GetProcAddress(hInstance, "cltSocketRev");
cltSocketDestory =(CltSocketDestory)::GetProcAddress(hInstance, "cltSocketDestory");
void *handle = NULL;
unsigned char buf[2048];
int buflen = 9;
unsigned char out[2048];
int outlen;
int ret = 0;
strcpy((char *)buf, "hello");
ret = cltSocketInit(&handle);
ret = cltSocketSend(handle, buf, buflen);
ret = cltSocketRev(handle, out, &outlen);
ret = cltSocketDestory(handle);
}
函数指针反向调用
回调函数
socketclient.c
typedef struct _SCK_HANDLE {
char version[16];
char serverip[16];
int serverport;
unsigned char * buf ;
int buflen;
}SCK_HANDLE;
//客户端初始化
ITCAST_FUNC_EXPORT(int)
cltSocketInit(void **handle)
{
SCK_HANDLE *sh = NULL;
int rv = 0;
if (handle == NULL)
{
rv = -1;
return rv;
}
//分配内存并初始化
sh = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE));
if (sh == NULL)
{
rv = -2;
return rv;
}
memset(sh, 0, sizeof(SCK_HANDLE));
//域赋值
strcpy(sh->version, "0.0.1");
strcpy(sh->serverip, "192.168.0.211");
sh->serverport = 8888;
//传出
*handle = sh;
return rv;
}
//客户端发报文
ITCAST_FUNC_EXPORT(int)
cltSocketSend(void *handle, unsigned char *buf, int buflen)
{
int rv = 0;
SCK_HANDLE *sh = NULL;
if (handle == NULL)
{
rv = -4;
return rv;
}
if (buf == NULL || buflen<=0)
{
rv = -5;
return rv;
}
sh = (SCK_HANDLE *)handle;
sh->buf = (unsigned char *)malloc(sizeof(char)*buflen);
if (sh->buf == NULL)
{
rv = -6;
return rv;
}
//把发送的报文数据,存储 handle 上下文之中
memcpy(sh->buf, buf, buflen);
sh->buflen = buflen;
return rv;
}
//客户端收报文
ITCAST_FUNC_EXPORT(int)
cltSocketRev(void *handle, unsigned char *buf, int *buflen)
{
int rv = 0;
SCK_HANDLE *sh = NULL;
if (handle == NULL)
{
rv = -4;
return rv;
}
if (buflen == NULL)
{
rv = -5;
return rv;
}
sh = (SCK_HANDLE *)handle;
//赋值 把上下文中的数据,copy到buf空间中
//支持二次调用,第一次调用求长度 第二次调用可以把数据copy buf中
if (buf != NULL)
{
memcpy(buf, sh->buf, sh->buflen);
//buf[ci->buflen] = '\0';
}
*buflen = sh->buflen;
return rv;
}
//客户端释放资源
ITCAST_FUNC_EXPORT(int)
cltSocketDestory(void *handle)
{
SCK_HANDLE *sh = NULL;
sh = handle;
if (sh != NULL)
{
free(sh->buf);
free(sh);
}
return 0;
}
//第二套api实现
//客户端初始化
ITCAST_FUNC_EXPORT(int)
cltSocketInit2(void **handle) //5day after
{
SCK_HANDLE *sh = NULL;
int rv = 0;
if (handle == NULL)
{
rv = -1;
return rv;
}
//分配内存并初始化
sh = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE));
if (sh == NULL)
{
rv = -2;
return rv;
}
memset(sh, 0, sizeof(SCK_HANDLE));
//域赋值
strcpy(sh->version, "0.0.1");
strcpy(sh->serverip, "192.168.0.211");
sh->serverport = 8888;
//传出
*handle = sh;
return rv;
}
//客户端发报文
ITCAST_FUNC_EXPORT(int)
cltSocketSend2(void *handle, unsigned char *buf, int buflen)
{
int rv = 0;
SCK_HANDLE *sh = NULL;
if (handle == NULL)
{
rv = -4;
return rv;
}
if (buf == NULL || buflen<=0)
{
rv = -5;
return rv;
}
sh = (SCK_HANDLE *)handle;
sh->buf = (unsigned char *)malloc(sizeof(char)*buflen);
if (sh->buf == NULL)
{
rv = -6;
return rv;
}
//把发送的报文数据,存储 handle 上下文之中
memcpy(sh->buf, buf, buflen);
sh->buflen = buflen;
return rv;
}
//客户端收报文
ITCAST_FUNC_EXPORT(int)
cltSocketRev2(void *handle, unsigned char **buf, int *buflen)
{
int rv = 0;
SCK_HANDLE *sh = NULL;
if (handle == NULL)
{
rv = -4;
return rv;
}
if (buflen == NULL)
{
rv = -5;
return rv;
}
sh = (SCK_HANDLE *)handle;
//分配内存数据传出
*buf = (char *)malloc(sh->buflen);
if (*buf == NULL)
{
rv = -6;
return rv;
}
memcpy(*buf, sh->buf, sh->buflen);
*buflen = sh->buflen;
return rv;
}
ITCAST_FUNC_EXPORT(int)
cltSocketRev2_Free(unsigned char **buf)
{
int rv = 0;
unsigned char * tmp = *buf;
if (buf == NULL)
{
rv = -7;
return rv;
}
if (tmp != NULL)
{
free(tmp);
}
*buf = NULL;
}
//客户端释放资源
ITCAST_FUNC_EXPORT(int)
cltSocketDestory2(void **handle)
{
SCK_HANDLE *sh = NULL;
sh = *handle;
if (sh != NULL)
{
free(sh->buf);
free(sh);
}
*handle = NULL;
return 0;
}
test.c
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "socketclientdll.h"
//typedef int (*EncData)(unsigned char *inData,int inDataLen,unsigned char *outData,int *outDataLen,void *Ref, int RefLen);
int myEncData(unsigned char *inData,
int inDataLen,
unsigned char *outData,
int *outDataLen,
void *Ref,
int RefLen)
{
memcpy(outData, "1111", 10);
*outDataLen = 10;
return 0;
}
int main()
{
int rv = 0;
void *handle = NULL;
unsigned char buf[2048];
int buflen = 0;
unsigned char buf2[2048] = {0};
int buflen2 = 0;
strcpy(buf, "aaaa");
buflen = 10;
rv = cltSocketInit(&handle);
if (rv != 0)
{
printf("func cltSocketInit():%d", rv);
return rv;
}
/*
// cvtres.exe
rv = clitSocket_SetEncFunc(handle, myEncData, NULL, 0);
if (rv != 0)
{
printf("func cltSocketInit():%d", rv);
goto End;
}
*/
rv = cltSocketSend(handle, buf, buflen);
if (rv != 0)
{
printf("func cltSocketSend():%d", rv);
goto End;
}
/*
rv = cltSocketSend_enc(handle, buf, buflen, myEncData, NULL, 0);
if (rv != 0)
{
printf("func cltSocketSend_enc():%d", rv);
goto End;
}
*/
rv = cltSocketRev(handle, buf2 , &buflen2);
if (rv != 0)
{
printf("func cltSocketRev():%d", rv);
goto End;
}
printf("\n%s", buf2);
End:
rv = cltSocketDestory(handle);
if (rv != 0)
{
printf("func cltSocketDestory():%d", rv);
return rv;
}
//system("pause");
return 0;
}