There are two distinct language rules involved here.
One is that a parameter that appears to be of function type is adjusted at compile time to a pointer to the function:
After determining the type of each parameter, any parameter of type
“array of T” or “function returning T” is adjusted to be “pointer to
T” or “pointer to function returning T,” respectively.
That's the rule that makes these function declarations:
void foo(void (*p)());
and
void foo(void (p)());
equivalent.
The other is that an expression of function type is, in most contexts, implicitly converted to a pointer to the function:
An lvalue of function type T can be converted to a prvalue of type
“pointer to T.” The result is a pointer to the function.
Given a function declaration:
void func();
this rule is what makes all these calls:
foo(&func);
foo(func);
foo(*func);
foo(**func);
equivalent. On the last one, the expression func
is of function type, so it's converted to a pointer. The inner *
dereferences that pointer yielding an expression of function type, which is then implicity converted to a pointer again. And the outer *
does the same thing.
In fact, the expression foo
is also converted to a pointer -- which is just what the function-call operator requires as the operand preceding the (
.