Передача указателя функции - программирование
Подтвердить что ты не робот

Передача указателя функции

Я немного смущен тем, как передать указатель на функцию указателя. У меня есть функция, которая принимает указатель на функцию, которую я понимаю без проблем (ExecBlock). Но мне предоставлен еще один прототип функции (ExecBlock2), которая принимает разыменованный указатель (я точно не знаю, что это такое), а также принимает аргумент, если переданная функция имеет какой-либо. Если кто-то может объяснить приоритет и точно, что бы разыменовали функцию указателя. Разве это не просто передача самой функции?. Что делает (void *) в этом случае?

int ExecBlock (void (*f) (void), int isSet)
{
    return ExecBlock2( HOW TO PASS HERE? , NULL, isSet);
}

int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
    ... more code
}

Спасибо!

4b9b3361

Ответ 1

void (*f) (void)

означает указатель на функцию без аргументов, возвращающих void.

void *(*f)(void *)

означает указатель на функцию, принимающую указатель void и возвращающий указатель на void.

Поскольку типы разные, компилятор не позволит вам передавать один на другой без кастования. (Обратите внимание, что кастинг на самом деле не является правильным ответом здесь, а как @detly указывает, приводит к поведению undefined.)

Что касается указателей разыменования функций, вам не нужно явно помещать "*" перед указателем функции, чтобы вызвать его. Например, вы можете вызвать указатель на функцию f, выполнив

f();

Пример указателя функции

Скажем, у вас есть функция f, которую вы хотите передать функции takes_a_function. takes_a_function, вероятно, будет иметь тип типа

void takes_a_function(void (*f)(void *data), void *data);

Обратите внимание, что есть два аргумента для takes_a_function, указатель на функцию и указатель на void для некоторых данных. Также обратите внимание, что функция f принимает в качестве аргумента указатель void. Идея состоит в том, что вы можете передать данные на takes_a_function, и она пройдет ее до f. Например, takes_a_function может быть определен как

void takes_a_function(void (*f)(void *), void *data) {
  f(data);
}

Теперь напишите функцию, чтобы перейти к takes_a_function. Наша функция будет просто распечатывать int, который передается ему.

void prints_an_int(void *data) {
  // The idiom for converting a void pointer to another kind
  // of pointer.  NO NEED TO CAST.  Note this behavior is only
  // defined if the pointer data really does point to an int.
  int *i = data;
  printf("%d", *i);
}

int i = 0;
takes_a_function(prints_an_int, &i);

Несколько ключевых моментов в этом примере:

  • prints_an_int имеет тот же тип, что и указатель функции, ожидаемый takes_a_function. Не нужно бросать.
  • Нет необходимости использовать оператор & для создания ссылки на функцию. Вот почему мы можем напрямую передать prints_an_int в takes_a_function. Но мы могли бы также сказать takes_a_function(&prints_an_int, &i), и было бы одинаково.
  • void* в основном означает "указатель на неизвестный тип". Чтобы на самом деле что-то с этим делать, вы должны назначить переменную типа void* другой переменной-указателю, тип которой вы ожидаете. Это гарантируется, только если вы действительно перейдете к правильному типу указателя! В этом примере мы можем назначить data int*, поскольку данные действительно указывают на int. Если вам нужно больше данных, чем просто целое число, общий шаблон состоит в том, чтобы создать свой собственный тип структуры, который включает все нужные вам поля, и вместо этого передать это.
  • В качестве специального случая компилятор не требует от вас приведения при назначении указателей void другим указателям и наоборот. Но опять же, вы получите только определенное поведение, если вы в конечном итоге преобразуете указатель void обратно в правильный тип.

Ответ 2

Например, у вас есть функция

void * abc(void *)
{
//... 
}

int ExecBlock (void (*f) (void), int isSet)
    {
        return ExecBlock2( abc , NULL, isSet); //use name of the function which have void * as parameter type list and return type  void *   
        }

int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
    ... more code
}  

См. function-pointers