函数指针做函数参数 使用总结及其意义
1、函数指针
函数指针用于指向一个函数
函数名是函数体的入口地址
1)可通过函数类型定义函数指针: FuncType* pointer;
2)也可以直接定义:type (*pointer)(parameter list);
pointer为函数指针变量名
type为指向函数的返回值类型
parameter list为指向函数的参数类型列表
例:
#include
#include
#include
using namespace std;
int Add(int a, int b)
{
int c = 0;
c = a \+ b;
return c;
}
int main()
{
//直接调用
int sum = Add(1, 2);//函数名称代表函数的入口地址,就是一个函数指针 ADD
*cout* << "函数之和sum:" << sum << *endl*;
//声明一个函数类型 间接调用。
\{
typedef int(MyFuncType)(int a, int b);
MyFuncType \*myFuncVar = *NULL*;
myFuncVar = Add;
int sum1=myFuncVar(2, 4);
*cout* << "函数之和sum1:" << sum1 << *endl*;
\}
//声明一个函数指类型。
\{
typedef int(\*PFuncType)(int a, int b);//声明函数指针 C编译器不会分配内存
PFuncType myFunc = *NULL*;
myFunc = &Add;
int sum2 = myFunc(3, 5);
*cout* << "函数之和sum2:" << sum2 << *endl*;
\}
//定义一个函数指针,用来只想一个函数的入口地址
\{
int(\*MYPFUNC)(int a, int b);
MYPFUNC = Add;
int sum3=MYPFUNC(10, 5);
*cout* << "函数之和sum3:" << sum3 << *endl*;
\}
return 0;
}
2、函数指针做函数参数
函数指针做函数参数 :当函数指针 做为函数的参数,传递给一个被调用函数,被调用函数就可以通过这个指针调用外部的函数,这就形成了回调。
例:
#include
#include
#include
using namespace std;
int Add(int a, int b)
{
int c = 0;
c = a \+ b;
*printf*("FUNC Add Done!\\n");
return c;
}
int Add2(int a, int b)
{
int c = 0;
c = a \+ b;
*printf*("FUNC Add2 Done!\\n");
return c;
}
int Add3(int a, int b)
{
int c = 0;
c = a \+ b;
*printf*("FUNC Add3 Done!\\n");
return c;
}
int Add4(int a, int b)
{
int c = 0;
c = a \+ b;
*printf*("FUNC Add4 Done!\\n");
return c;
}
int myMainFunc(int(*myFuncAdd)(int a, int b))
{
int sum= myFuncAdd(10, 20);
return sum;
}
int main()
{
myMainFunc(Add);
myMainFunc(Add2);
myMainFunc(Add3);
myMainFunc(Add4);
return 0;
}
运行结果:
思路剖析:
1、指针函数的用法将函数的调用和函数的实现有效分离,实现解耦。
2、int myMainFunc(int(*myFuncAdd)(int a, int b))是一个库中的函数,就只有使用回调了,通过函数指针参数将外部函数地址传入来实现调用
3、函数 Add 的代码作了修改,也不必改动库的代码,就可以正常实现调用,便于程序的维护和升级。
3、函数指针做函数参数在实际项目中的运用。
第一种 正向调用
例:
有个socketclient.dll,用dependency walker可以查看到dll的方法。
第一步 Load DLL
HINSTANCE hInstance;
*string* pathStr= "socketclient.dll";
*LPCSTR* sss = pathStr.*c\_str*();
hInstance =*LoadLibrary*("socketclient.dll");
if (hInstance == *NULL*)
\{
*printf*("LoadLibrary() 失败");
return 0;
\}
在这里注意编码的问题。
右键属性如下图:
将字符集修改为使用多字节字符集。
如果使用Unicode字符集则需要做修改,Unicode时,LoadLibrary的参数是LPCWSTR。所以需要做转化。
LPCWSTR stringToLPCWSTR(string orig)
{
*size\_t* origsize = orig.*length*() + 1;
const *size\_t* newsize = 100;
*size\_t* convertedChars = 0;
wchar\_t \*wcstring = (wchar\_t \*)*malloc*(sizeof(wchar\_t)\*(orig.*length*() - 1));
*mbstowcs\_s*(&convertedChars, wcstring, origsize, orig.*c\_str*(), *\_TRUNCATE*);
return wcstring;
}
int main()
{
*HINSTANCE* hInstance;
*string* pathStr= "socketclient.dll";
*LPCTSTR* sss = stringToLPCWSTR(pathStr);
hInstance =*LoadLibrary*(sss);
if (hInstance == *NULL*)
\{
*printf*("LoadLibrary() 失败");
return 0;
\}
}
第二步 声明函数指针类型
//客户端初始化 获取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*/);
第三步 实现函数的调用。
CltSocketInit cltSocketInit = (CltSocketInit)::GetProcAddress(hInstance, “cltSocketInit”);
if (cltSocketInit == *NULL*)
\{
return 0;
\}
CltSocketSend cltSocketSend = (CltSocketSend)::*GetProcAddress*(hInstance, "cltSocketSend");
CltSocketRev cltSocketRev = (CltSocketRev)::*GetProcAddress*(hInstance, "cltSocketRev");
CltSocketDestory cltSocketDestory = (CltSocketDestory)::*GetProcAddress*(hInstance, "cltSocketDestory");
//执行动态库函数调用
unsigned char buf\[128\];
int buflen = 128;
unsigned char outbuf\[4096\];
int outbuflen = 4096;
*strcpy*((char \*)buf, "aaaaaaaaaafffffffffdddddd");
buflen = 9;
void \*handle = *NULL*;
int ret = 0;
ret = cltSocketInit(&handle);
ret = cltSocketSend(handle, buf, buflen);
ret = cltSocketRev(handle, outbuf, &outbuflen);
ret = cltSocketDestory(handle);
if (*memcmp*(buf, outbuf, outbuflen) == 0)
\{
*printf*("发送数据和接受的数据一样 ok\\n");
\}
else
\{
*printf*("发送数据和接受的数据不一样\\n");
\}
完整代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;
//客户端初始化 获取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*/);
LPCWSTR stringToLPCWSTR(string orig)
{
*size\_t* origsize = orig.*length*() + 1;
const *size\_t* newsize = 100;
*size\_t* convertedChars = 0;
wchar\_t \*wcstring = (wchar\_t \*)*malloc*(sizeof(wchar\_t)\*(orig.*length*() - 1));
*mbstowcs\_s*(&convertedChars, wcstring, origsize, orig.*c\_str*(), *\_TRUNCATE*);
return wcstring;
}
int main()
{
*HINSTANCE* hInstance;
*string* pathStr= "socketclient.dll";
*LPCTSTR* sss = stringToLPCWSTR(pathStr);
hInstance =*LoadLibrary*(sss);
if (hInstance == *NULL*)
\{
*printf*("LoadLibrary() 失败");
return 0;
\}
CltSocketInit cltSocketInit = (CltSocketInit)::*GetProcAddress*(hInstance, "cltSocketInit");
if (cltSocketInit == *NULL*)
\{
return 0;
\}
CltSocketSend cltSocketSend = (CltSocketSend)::*GetProcAddress*(hInstance, "cltSocketSend");
CltSocketRev cltSocketRev = (CltSocketRev)::*GetProcAddress*(hInstance, "cltSocketRev");
CltSocketDestory cltSocketDestory = (CltSocketDestory)::*GetProcAddress*(hInstance, "cltSocketDestory");
//执行动态库函数调用
unsigned char buf\[128\];
int buflen = 128;
unsigned char outbuf\[4096\];
int outbuflen = 4096;
*strcpy*((char \*)buf, "aaaaaaaaaafffffffffdddddd");
buflen = 9;
void \*handle = *NULL*;
int ret = 0;
ret = cltSocketInit(&handle);
ret = cltSocketSend(handle, buf, buflen);
ret = cltSocketRev(handle, outbuf, &outbuflen);
ret = cltSocketDestory(handle);
if (*memcmp*(buf, outbuf, outbuflen) == 0)
\{
*printf*("发送数据和接受的数据一样 ok\\n");
\}
else
\{
*printf*("发送数据和接受的数据不一样\\n");
\}
return 0;
}
运行结果:
还没有评论,来说两句吧...