О указателях к функциям в объявлениях функций
#include<stdio.h>
#include<stdlib.h>
int fun1()
{
printf("I am fun1.");
return 0;
}
int fun2(int fun())
{
fun();
return 0;
}
int main()
{
fun2(fun1);
return 0;
}
Вышеупомянутая программа может работать. Насколько я могу судить, я могу понять int fun2(int (*fun)())
, но я не знаю, как работает int fun2(int fun())
. Спасибо.
Ответы
Ответ 1
Когда вы пишете int fun2(int fun())
, параметр int fun()
преобразуется в int (*fun)()
, он становится в точности эквивалентным этому:
int fun2(int (*fun)());
Преобразование более famiiar происходит в случае массива, когда вы объявляете его как параметр функции. Например, если у вас есть это:
int f(int a[100]);
Даже здесь тип параметра преобразуется в int*
, и он становится следующим:
int f(int *a);
Причина, по которой тип функции и тип массива преобразуются в тип указателя функции, и тип указателя, соответственно, состоит в том, что стандарт не позволяет передавать функции и массив функции, и вы не можете возвращать функцию и массив из функция. В обоих случаях они распадаются на свою версию указателя.
Стандарт С++ 03 гласит в §13.1/3 (и он аналогичен и в С++ 11),
Объявления параметров, которые отличаются только этим, являются типом функции, а другой - указателем на тот же тип функции эквивалент. То есть, тип функции настраивается, чтобы стать указателем на тип функции (8.3.5).
И более интересное обсуждение здесь:
Ответ 2
int fun2(int (*fun)())
и int fun2(int fun())
точно совпадают. Когда вы объявляете аргумент функции из типа функции, компилятор использует его, как если бы он был указателем на тот же тип функции.
Ответ 3
Эти два определения функций эквивалентны в C:
int fun2(int fun()) { ... }
и
int fun2(int (*fun)()) { ... }
В первой функции параметр настраивается на указатель функции. См. Пункт C Стандарт:
(C99, 6.7.5.3p8) "Объявление возвращаемого типа параметра как функции функции" "должно быть отрегулировано на" "указатель на возвращаемый тип функции, как в 6.3.2.1.
Ответ 4
Посмотрите на него на более низком уровне (и в архитектуре на основе x86):
int fun2(int fun())
int fun() адрес вставляется в стек и передается функции fun2().
int fun2(int (*fun)())
int fun() указатель адрес вставляется в стек и передается функции fun2().
Результат тот же, кроме второго, вы передаете адрес fun() по ссылке, а в первом передаете его по значению.