函数指针做函数参数 使用总结及其意义

朱雀 2022-12-04 09:19 250阅读 0赞

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)

{

  1. int c = 0;
  2. c = a \+ b;
  3. return c;

}

int main()

{

  1. //直接调用
  2. int sum = Add(1, 2);//函数名称代表函数的入口地址,就是一个函数指针 ADD
  3. *cout* << "函数之和sum:" << sum << *endl*;
  4. //声明一个函数类型 间接调用。
  5. \{
  6. typedef int(MyFuncType)(int a, int b);
  7. MyFuncType \*myFuncVar = *NULL*;
  8. myFuncVar = Add;
  9. int sum1=myFuncVar(2, 4);
  10. *cout* << "函数之和sum1:" << sum1 << *endl*;
  11. \}
  12. //声明一个函数指类型。
  13. \{
  14. typedef int(\*PFuncType)(int a, int b);//声明函数指针 C编译器不会分配内存
  15. PFuncType myFunc = *NULL*;
  16. myFunc = &Add;
  17. int sum2 = myFunc(3, 5);
  18. *cout* << "函数之和sum2:" << sum2 << *endl*;
  19. \}
  20. //定义一个函数指针,用来只想一个函数的入口地址
  21. \{
  22. int(\*MYPFUNC)(int a, int b);
  23. MYPFUNC = Add;
  24. int sum3=MYPFUNC(10, 5);
  25. *cout* << "函数之和sum3:" << sum3 << *endl*;
  26. \}
  27. return 0;

}

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hoaGhoaGhoaGh3d3d3d3d3d3d3_size_16_color_FFFFFF_t_70

2、函数指针做函数参数

函数指针做函数参数 :当函数指针 做为函数的参数,传递给一个被调用函数,被调用函数就可以通过这个指针调用外部的函数,这就形成了回调。

例:

#include

#include

#include

using namespace std;

int Add(int a, int b)

{

  1. int c = 0;
  2. c = a \+ b;
  3. *printf*("FUNC Add Done!\\n");
  4. return c;

}

int Add2(int a, int b)

{

  1. int c = 0;
  2. c = a \+ b;
  3. *printf*("FUNC Add2 Done!\\n");
  4. return c;

}

int Add3(int a, int b)

{

  1. int c = 0;
  2. c = a \+ b;
  3. *printf*("FUNC Add3 Done!\\n");
  4. return c;

}

int Add4(int a, int b)

{

  1. int c = 0;
  2. c = a \+ b;
  3. *printf*("FUNC Add4 Done!\\n");
  4. return c;

}

int myMainFunc(int(*myFuncAdd)(int a, int b))

{

  1. int sum= myFuncAdd(10, 20);
  2. return sum;

}

int main()

{

  1. myMainFunc(Add);
  2. myMainFunc(Add2);
  3. myMainFunc(Add3);
  4. myMainFunc(Add4);
  5. return 0;

}

运行结果:

20200907181715533.png

思路剖析:

1、指针函数的用法将函数的调用和函数的实现有效分离,实现解耦。

2、int myMainFunc(int(*myFuncAdd)(int a, int b))是一个库中的函数,就只有使用回调了,通过函数指针参数将外部函数地址传入来实现调用

3、函数 Add 的代码作了修改,也不必改动库的代码,就可以正常实现调用,便于程序的维护和升级。

3、函数指针做函数参数在实际项目中的运用。

第一种 正向调用

例:

有个socketclient.dll,用dependency walker可以查看到dll的方法。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hoaGhoaGhoaGh3d3d3d3d3d3d3_size_16_color_FFFFFF_t_70 1

第一步 Load DLL

HINSTANCE hInstance;

  1. *string* pathStr= "socketclient.dll";
  2. *LPCSTR* sss = pathStr.*c\_str*();
  3. hInstance =*LoadLibrary*("socketclient.dll");
  4. if (hInstance == *NULL*)
  5. \{
  6. *printf*("LoadLibrary() 失败");
  7. return 0;
  8. \}

在这里注意编码的问题。

右键属性如下图:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hoaGhoaGhoaGh3d3d3d3d3d3d3_size_16_color_FFFFFF_t_70 2

将字符集修改为使用多字节字符集。

如果使用Unicode字符集则需要做修改,Unicode时,LoadLibrary的参数是LPCWSTR。所以需要做转化。

LPCWSTR stringToLPCWSTR(string orig)

{

  1. *size\_t* origsize = orig.*length*() + 1;
  2. const *size\_t* newsize = 100;
  3. *size\_t* convertedChars = 0;
  4. wchar\_t \*wcstring = (wchar\_t \*)*malloc*(sizeof(wchar\_t)\*(orig.*length*() - 1));
  5. *mbstowcs\_s*(&convertedChars, wcstring, origsize, orig.*c\_str*(), *\_TRUNCATE*);
  6. return wcstring;

}

int main()

{

  1. *HINSTANCE* hInstance;
  2. *string* pathStr= "socketclient.dll";
  3. *LPCTSTR* sss = stringToLPCWSTR(pathStr);
  4. hInstance =*LoadLibrary*(sss);
  5. if (hInstance == *NULL*)
  6. \{
  7. *printf*("LoadLibrary() 失败");
  8. return 0;
  9. \}

}

第二步 声明函数指针类型

//客户端初始化 获取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”);

  1. if (cltSocketInit == *NULL*)
  2. \{
  3. return 0;
  4. \}
  5. CltSocketSend cltSocketSend = (CltSocketSend)::*GetProcAddress*(hInstance, "cltSocketSend");
  6. CltSocketRev cltSocketRev = (CltSocketRev)::*GetProcAddress*(hInstance, "cltSocketRev");
  7. CltSocketDestory cltSocketDestory = (CltSocketDestory)::*GetProcAddress*(hInstance, "cltSocketDestory");
  8. //执行动态库函数调用
  9. unsigned char buf\[128\];
  10. int buflen = 128;
  11. unsigned char outbuf\[4096\];
  12. int outbuflen = 4096;
  13. *strcpy*((char \*)buf, "aaaaaaaaaafffffffffdddddd");
  14. buflen = 9;
  15. void \*handle = *NULL*;
  16. int ret = 0;
  17. ret = cltSocketInit(&handle);
  18. ret = cltSocketSend(handle, buf, buflen);
  19. ret = cltSocketRev(handle, outbuf, &outbuflen);
  20. ret = cltSocketDestory(handle);
  21. if (*memcmp*(buf, outbuf, outbuflen) == 0)
  22. \{
  23. *printf*("发送数据和接受的数据一样 ok\\n");
  24. \}
  25. else
  26. \{
  27. *printf*("发送数据和接受的数据不一样\\n");
  28. \}

完整代码如下:

#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)

{

  1. *size\_t* origsize = orig.*length*() + 1;
  2. const *size\_t* newsize = 100;
  3. *size\_t* convertedChars = 0;
  4. wchar\_t \*wcstring = (wchar\_t \*)*malloc*(sizeof(wchar\_t)\*(orig.*length*() - 1));
  5. *mbstowcs\_s*(&convertedChars, wcstring, origsize, orig.*c\_str*(), *\_TRUNCATE*);
  6. return wcstring;

}

int main()

{

  1. *HINSTANCE* hInstance;
  2. *string* pathStr= "socketclient.dll";
  3. *LPCTSTR* sss = stringToLPCWSTR(pathStr);
  4. hInstance =*LoadLibrary*(sss);
  5. if (hInstance == *NULL*)
  6. \{
  7. *printf*("LoadLibrary() 失败");
  8. return 0;
  9. \}
  10. CltSocketInit cltSocketInit = (CltSocketInit)::*GetProcAddress*(hInstance, "cltSocketInit");
  11. if (cltSocketInit == *NULL*)
  12. \{
  13. return 0;
  14. \}
  15. CltSocketSend cltSocketSend = (CltSocketSend)::*GetProcAddress*(hInstance, "cltSocketSend");
  16. CltSocketRev cltSocketRev = (CltSocketRev)::*GetProcAddress*(hInstance, "cltSocketRev");
  17. CltSocketDestory cltSocketDestory = (CltSocketDestory)::*GetProcAddress*(hInstance, "cltSocketDestory");
  18. //执行动态库函数调用
  19. unsigned char buf\[128\];
  20. int buflen = 128;
  21. unsigned char outbuf\[4096\];
  22. int outbuflen = 4096;
  23. *strcpy*((char \*)buf, "aaaaaaaaaafffffffffdddddd");
  24. buflen = 9;
  25. void \*handle = *NULL*;
  26. int ret = 0;
  27. ret = cltSocketInit(&handle);
  28. ret = cltSocketSend(handle, buf, buflen);
  29. ret = cltSocketRev(handle, outbuf, &outbuflen);
  30. ret = cltSocketDestory(handle);
  31. if (*memcmp*(buf, outbuf, outbuflen) == 0)
  32. \{
  33. *printf*("发送数据和接受的数据一样 ok\\n");
  34. \}
  35. else
  36. \{
  37. *printf*("发送数据和接受的数据不一样\\n");
  38. \}
  39. return 0;

}

运行结果:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hoaGhoaGhoaGh3d3d3d3d3d3d3_size_16_color_FFFFFF_t_70 3

第二种 反向调用

发表评论

表情:
评论列表 (有 0 条评论,250人围观)

还没有评论,来说两句吧...

相关阅读