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

举报
AI浩 发表于 2021/12/23 01:24:18 2021/12/23
【摘要】 目录 1、函数指针 2、函数指针做函数参数 3、函数指针做函数参数在实际项目中的运用。 第一种 正向调用 第一步 Load DLL 第二步 声明函数指针类型 第三步 实现函数的调用。 完整代码如下: 第二种 反向调用 1、函数指针 函数指针用于指向一个函数 函数名是函数体的入口地址 1)可通过函数类型定义函数...

目录

1、函数指针

2、函数指针做函数参数

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

第一种 正向调用

第一步 Load DLL

第二步 声明函数指针类型

第三步 实现函数的调用。

完整代码如下:

第二种 反向调用


1、函数指针

函数指针用于指向一个函数

函数名是函数体的入口地址

1)可通过函数类型定义函数指针: FuncType* pointer;

2)也可以直接定义:type (*pointer)(parameter list);

pointer为函数指针变量名

type为指向函数的返回值类型

parameter list为指向函数的参数类型列表

例:

#include <windows.h>

#include <stdio.h>

#include <iostream>

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 <windows.h>

#include <stdio.h>

#include <iostream>

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 <stdio.h>

#include <windows.h>

#include <iostream>

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;

}

运行结果:

 

第二种 反向调用

文章来源: wanghao.blog.csdn.net,作者:AI浩,版权归原作者所有,如需转载,请联系作者。

原文链接:wanghao.blog.csdn.net/article/details/111073423

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。