О указателях к функциям в объявлениях функций

#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() по ссылке, а в первом передаете его по значению.