Можно ли хранить аргументы функции в указателе на функцию? - PullRequest
4 голосов
/ 04 мая 2019

Просто из любопытства я пытаюсь понять, как работают указатели на функции в C.

Чтобы связать функцию с typedef, я объявил в ней указатель, а затем сохранил там адрес нужной функции.

Вот чего я смог достичь:

typedef struct
{

    void (*get)(char*, int);
    char string[10];

} password;

int main()
{
    password userPassword;

    userPassword.get = &hiddenStringInput; 

    userPassword.get(userPassword.string, 10);

    return EXIT_SUCCESS;
}

Хотя это на самом деле работает отлично, я бы хотел, чтобы userPassword.get был ярлыком, который при использовании вызывает функцию hiddenStringInput и заполняет запрошенные аргументы (в данном случае массив символов и целое число) ,

По сути, поскольку я всегда собираюсь использовать userPassword.get в сочетании с аргументами «userPassword.string» и «10», я пытаюсь найти способ каким-то образом сохранить эти параметры в указателе, который указывает к функции hiddenString. Это вообще возможно?

Ответы [ 3 ]

2 голосов
/ 04 мая 2019

Я обычно вижу, как это делается, предоставляя функцию "dispatch":

void get(password * pw) {
  pw->get(pw->string, 10);
}

Затем, после установки userPassword.get на вашу функцию, вы вызываете просто:

get(userPassword);

Очевидно, это добавляет некоторый шаблонный код, когда выполняется несколько функций. Позволяет реализовать и другие забавные вещи типа «класс».

1 голос
/ 04 мая 2019

Вы можете сделать это в Clang, используя расширение языка «Blocks».Как отмечалось, были попытки стандартизировать этот (и он не был получен с враждебностью или чем-то еще), но они движутся медленно.

В переводе на использование блоков ваш пример может выглядетькак это:

#include <stdlib.h>

#include <Block.h>

typedef void (^GetPw)(int);             // notice how Block pointer types are used
typedef void (*GetPw_Impl)(char*, int); // the same way as function pointer types

typedef struct
{
    GetPw get;
    char string[10];
} password;

extern void hiddenStringInput(char*, int);

extern void setPw(char dst [static 10], char * src);

GetPw bindPw (GetPw_Impl get_impl, char * pw)
{
  return Block_copy (^ (int key) {
    get_impl (pw, key);
  });
}

int main()
{
    password userPassword;

    setPw(userPassword.string, "secret");

    userPassword.get = bindPw(hiddenStringInput, userPassword.string); 

    userPassword.get(10);

    return EXIT_SUCCESS;
}

Существуют некоторые тонкости в способе захвата массивов, которые могут запутать этот случай;в примере захватывается пароль с помощью обычного указателя и предполагается, что userPassword отвечает за владение им отдельно от блока.

Поскольку блок захватывает значения, ему необходимо предоставить и освободить динамическое хранилище для копийзахваченные значения, которые будут созданы при копировании самого блока из области, в которой он был создан;это делается с помощью функций Block_copy и Block_release.

Типы блоков (синтаксически функциональные указатели, но с использованием ^ вместо *) являются просто указателями - нетспособ доступа к базовому объекту блока, точно так же как и к основным функциям C.


Это Clang API - стандартизация изменит это немного, и, вероятно, уменьшит потребность в динамическом распределении памяти для копирования блока вокруг(но Clang API отражает, как они в настоящее время наиболее часто используются).

0 голосов
/ 04 мая 2019

Итак, я только что понял, что могу писать функции непосредственно внутри структур

typedef struct
{

    char string[10];

    void get(void)
    {
        hiddenStringInput(string, 10);

        return;
    }

    void set(const char* newPassword)
    {
        strcpy(string, newPassword);

        return;
    }

    void show(void)
    {
        printf("%s", string);

        return;
    }



} password;

Теперь я могу просто вызывать userPassword.get (), userPassword.show () и userPassword.set ("что-то "), и то, что происходит, это именно то, что написано на этикетке.Есть ли причины, по которым я не должен этого делать?Похоже, это может пригодиться.

РЕДАКТИРОВАТЬ: Таким образом, это возможно только в C ++.Я не осознавал, что использую компилятор C ++, и, пытаясь делать случайные вещи, я придумал это решение.Так что это не совсем то, что я искал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...