Указатель функции как параметр функции Краткое описание использования и его значение

искусственный интеллект

1. Указатель функции

Указатель функции используется для указания на функцию

Имя функции — это адрес входа в тело функции.

1) Указатели функций могут быть определены типами функций: указатель FuncType*;

2) Его также можно определить напрямую: type (*pointer)(список параметров);

указатель - это имя переменной указателя функции

type — тип возвращаемого значения указателя на функцию

список параметров — это список типов параметров, указывающих на функцию

пример:

#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

    coutendl;

// Объявить тип функции для косвенного вызова.

    {

         typedef int(MyFuncType)(int a, int b);

         MyFuncType *myFuncVar = NULL;

         myFuncVar = Add;

         int sum1=myFuncVar(2, 4);

         coutendl;

    }

// Объявить функцию для ссылки на тип.

    {

Typedef int(*PFuncType)(int a, int b);//Объявить указатель на функцию Компилятор C не будет выделять память

         PFuncType myFunc = NULL;

         myFunc = &Add;

         int sum2 = myFunc(3, 5);

         coutendl;

    }

//Определяем указатель на функцию, чтобы нужен был только адрес входа функции

    {

         int(*MYPFUNC)(int a, int b);

         MYPFUNC = Add;

         int sum3=MYPFUNC(10, 5);

         coutendl;

    }

    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, и метод dll можно посмотреть с помощью зависимостей walker.

 

Первый шаг Загрузить DLL

HINSTANCE hInstance;

    string pathStr= "socketclient.dll";

    LPCSTR sss = pathStr.c_str();

    hInstance =LoadLibrary("socketclient.dll");

    if (hInstance == NULL)

    {

         printf("Загрузить библиотеку() не удалось");

         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("Загрузить библиотеку() не удалось");

         return 0;

    }

}

Второй шаг — объявить тип указателя функции.

// Инициализация клиента получает дескриптор вверх и вниз

//объявляем тип указателя на функцию

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;

 

// Инициализация клиента получает дескриптор вверх и вниз

//объявляем тип указателя на функцию

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("Загрузить библиотеку() не удалось");

         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;

}

результат операции:

 

Второй обратный вызов