Определение функции, которая возвращает указатель на функцию, которая также возвращает указатель на функцию без typedefs
Я пытаюсь по-настоящему понять функциональные указатели без использования typedef
, но не могу этого понять. Я не понимаю, какая подпись необходима, чтобы передать, что я возвращаю указатель на указатель на функцию.
#include <stdio.h>
void odd() { printf("odd!\n"); }
void even() { printf("even!\n"); }
void (*get_pfn(int i))()
{
return i % 2 == 0 ? &even : &odd;
}
__SIGNATURE__
{
return &get_pfn;
}
int main()
{
get_pfn_pfn()(1)();
get_pfn_pfn()(2)();
return 0;
}
Чтобы это работало, каким должен быть __SIGNATURE__
?
Ответы
Ответ 1
Он должен возвращать указатель на функцию, которая принимает int
и возвращает указатель на функцию:
void (*(*get_pfn_pfn(void))(int))(void) {
return &get_pfn;
}
больше строк:
void (*
(*
get_pfn_pfn(void) // this is our function
)(int i) // this is get_pfn(int)
)(void) // this is odd() or even()
{
return &get_pfn;
}
void
можно опустить, и в этом случае указатель функции указывает на функцию, которая принимает неизвестное количество параметров. Что не то, что вы хотите. Чтобы объявить указатель на функцию, которая не принимает аргументов, вы должны добавить void
в список параметров функции. Точно так же лучше всего изменить get_pfn
на void (*get_pfn(int i))(void)
. Например, попробуйте позвонить из get_pfn(1)("some arg", "some other arg");
. Компилятор C не выдаст предупреждение, так как пустой ()
обозначает неизвестные аргументы. Чтобы сказать, что функция не принимает аргументов, вы должны (void)
.
Для многих последовательностей фигурных скобок, особенно ))(
, указатели на функции трудно анализировать. Вот почему многие предпочитают typedefs для указателей или типов функций:
typedef void get_pfn_func_t(void);
get_pfn_func_t *get_pfn(int i) {
return i % 2 == 0 ? &even : &odd;
}
typedef get_pfn_func_t *get_pfn_pfn_func_t(int i);
get_pfn_pfn_func_t *get_pfn_pfn(void) {
return &get_pfn;
}
Ответ 2
Тип возвращаемого значения функции get_pfn
-
void (*) ();
Так что тип &get_pfn
-
void (*(*)(int))()
Теперь эта функция возвращает этот тип, поэтому ее подпись будет -
void (*(*(foo)())(int))()
Вы можете убедиться в этом, введя это в cdecl.org
Ответ 3
Функциональные указатели без typedef
могут быть сложными для работы. Чтобы понять их, вы работаете изнутри.
Итак, давайте разберемся, как мы придумаем правильную сигнатуру функции.
get_pfn_pfn
- это функция:
get_pfn_pfn()
Который не принимает параметров:
get_pfn_pfn(void)
И возвращает указатель:
*get_pfn_pfn(void)
Для функции:
(*get_pfn_pfn(void))()
Который принимает параметр int
:
(*get_pfn_pfn(void))(int)
И возвращает указатель:
*(*get_pfn_pfn(void))(int)
Для функции:
(*(*get_pfn_pfn(void))(int))()
Который не принимает параметров:
(*(*get_pfn_pfn(void))(int))(void)
И ничего не возвращает (т.е. void
):
void (*(*get_pfn_pfn(void))(int))(void)
Конечно, использование typedef
значительно упрощает это.
Сначала введите тип для even
и odd
:
typedef void (*func1)(void);
Что мы можем затем применить к get_pfn
:
func1 get_pfn(int) { ... }
Затем введите для этой функции:
typedef func1 (*func2)(int);
Что мы можем применить к get_pfn_pfn
:
func2 get_pfn_pfn(void) { ... }
Ответ 4
это так:
void (*(*get_pfn_pfn(void))(int))()