When we use the name of a function to pass arguments, are we using a pointer to that function?
Example:
int foo(int a, int b);
int main(void)
{
int a = foo(1,3); //foo() it's a pointer to the function foo()?
return 0;
}
The term you're looking for is function designator. It is not a pointer type, but most of the time, it is converted to one.
Quoting the C11 standard, chapter §6.3.2.1, (emphasis mine)
A function designator is an expression that has function type. Except when it is the
operand of the sizeof operator, the _Alignof operator,65) or the unary & operator, a
function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.
Related, from the "function call" part of the spec, chapter 6.5.2.2
The expression that denotes the called function 92) shall have type pointer to function
returning void or returning a complete object type other than an array type.
which tells us, at the function call, the designator actually gets converted into a pointer.
Related
Say for this simple code:
int foo(void);
int (*p)(void);
p = foo;
p = &foo;
int a = p();
int b = (*p)();
In the above example, Line 3&4 are both valid, Line 5&6 are also both valid.
In fact if you try to play with variable pointers like that when you play with function pointers, your program will surely die. So why is it valid for function pointers?
A function (more precisely, a function designator) is converted to a pointer to a function (except when it is the operand of sizeof, _Alignof, or the unary &). So foo and &foo are the same thing because foo is automatically converted to &foo.
Similarly, p is a pointer to a function, so *p is the function, so it is automatically converted to the address of the function.
In fact, because *p is converted back to a pointer right away, you can apply * to it again, as in int b = (**p)();. And you can do that again and again and again: int b = (************p)();.
From the 2011 C standard (committee draft N1570), 6.3.2.1 4:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type “function returning type” is converted to an expression that has type “pointer to function returning type”.
This is just a consequence of the fact that C developers wanted to make it easy to use both functions like foo and pointers-to-functions like p. If you had to write foo() for one and (*p)() for the other, that would be a bit of a nuisance. Or at least more typing. Or, if you had to write (&foo)() for one and p() for the other, that is again more typing. So they just said whenever you write a function, we will automatically make it the pointer, and you can call it without typing any more.
I suppose they could have said the function call operator can accept either a function or a pointer to a function, but they chose the automatic conversion instead.
Corollary: If you do not know whether something is a function, or a pointer to a function, or a pointer to a pointer to a function, etc., just slap a hundred asterisks in front of it, and the compiler will stop when it gets to the function.
According to §6.5.2.2/1 of the C11 Standard, in a function call:
The expression that denotes the called function shall have type pointer to function returning void or returning a complete object type other than an array type.
Now, in most expressions a function designator is converted to a function pointer (§6.3.2.1/4):
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type ''function returning type'' is converted to an expression that has type ''pointer to function returning type''.
So, in a function call such as int a = p();, the function designator p is converted to a function pointer, which is needed in the expression before the postfix operator () for the function call.
But, according to §6.5.3.2/4 about the indirection operator:
If the operand points to a function, the result is a function designator
So, in a function call such as int b = (*p)();, the function designator p is converted to a function pointer, and the result of the indirection operator acting on this function pointer is a function designator, which itself is converted to the function pointer needed in the postfix expression for the function call.
By §6.5.2.2/1 above, foo is converted to a function pointer in the expression p = foo. But, in the expression p = &foo, the function designator is not converted to a function pointer. Here, §6.5.3.2/3 states that:
The unary & operator yields the address of its operand. If the operand has type ''type'', the result has type ''pointer to type''.... Otherwise, the result is a pointer to the object or function designated by its operand.
So the expression &foo evaluates to a pointer to the function designated by foo, as expected.
This question already has answers here:
Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?
(5 answers)
Closed 5 years ago.
I have test the following code:
#include <stdio.h>
void f(void g()) {
g();
}
void g(void) {
printf("hello, world\n");
}
int main() {
f(g);
return 0;
}
It works well. In the code above, why in c we can take the function name g as paramter and take the function prototype as parameter?
In book K&R, it says that we can use the pointer to function:
So I can define the function f like this:
void f(void (*g)()) {
g();
}
void g(void) {
printf("hello, world\n");
}
int main() {
void (*pf)() = g;
f(pf);
f(g); // Here f(g) also works.
return 0;
}
So in the first f definition form, the parameter prototype is void g(), in the second form the parameter prototype is void (*g)(). Why the two forms of definition of f are the same?
And in the second form, the parameter is a pointer to function, why f(g) also works?
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
4 A function designator is an expression that has function type.
Except when it is the operand of the sizeof operator65) or the unary &
operator, a function designator with type ‘‘function returning type’’
is converted to an expression that has type ‘‘pointer to function
returning type’’.
and (6.7.6.3 Function declarators (including prototypes))
8 A declaration of a parameter as ‘‘function returning type’’ shall be
adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.
Thus these function declarations
void f(void g());
and
void f(void ( *g )());
declare the same one function.
Because a function decays into a function pointer when it is not used within a function calling context:
void f(void a()) { a(); } //void a() decays into void (*a)()
void g(void (*a)()) { a(); } //equivalent to the above
void h(void a()) { (*a)(); } //*a is equivalent to a
void i(void a()) { (**a)(); } //**a is equivalent to *a
void j(void a()) { (***a)(); } //...
void k() { };
int main() {
f(k);
g(k);
h(k);
i(k);
j(k);
}
This compiles and runs fine, even though I've been using liberal amounts of the dereferencing operator on the argument function. Each time I use it, the resulting function decays back into a pointer when it hits the next dereferencing operator. Likewise, the function argument void a() decays into a pointer just like int array[] decays into int* array when used as a function argument.
When used as a function parameter, function name behaves as a pointer to the function itself.
These all are valid prototype
void f(void (g)());
void f(void (*g)());
void f(void (**g)());
void f(void (*****g)());
When you declare a function pointer then you can make a call using that pointer as
g();
(*g)();
(*****g)();
The C standard ISO/IEC 9899:2011, section 6.3.2.1 item 4 says:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator,65) or the unary & operator, a function designator with type “function returning type” is converted to an expression that has type “pointer to function returning type”.
So normally a function name (or other expression with function type, i.e. a function designator) is converted to a pointer to a function, except in the circumstances mentioned above.
So what happens when you apply the & operator to a function, as that is one of the cases excluded from the above clause. The answer is given by section 6.5.3.3 item 3, the relevant parts of which are:
The unary & operator yields the address of its operand. If the operand has type “type”, the result has type “pointer to type”. [...] Otherwise, the result is a pointer to the object or function designated by its operand.
(The "[...]" part I missed out discusses applying the & operator to the result of a unary * operator and to the result of the [] operator.)
So applying & to a function name (or other function designator) also gives you a pointer to the function.
So what happens when you dereference a function pointer with the unary * operator? It produces a function designator (section 6.5.3.3 item 4), which in most circumstances (as discussed above) gets converted back to a pointer to a function!
EDIT: I neglected to mention the case of declaring a parameter of a function to be a function returning type. As discussed in Vlad from Moscow's answer referring to section 6.7.6.3 item 8, that gets automatically adjusted to be a pointer to a function returning type.
This question already has answers here:
How does dereferencing of a function pointer happen?
(5 answers)
Closed 8 years ago.
In function pointers,
Why is (*fptr)(int a, int b) is same as (fptr)(int a, int b) if the function pointer is assigned to add function?
int (*fptr)(int ,int) = add;
while add(int a , int b) returns sum of two numbers.
Explanation
C doesn't have function objects, so it makes no sense to dereference a function pointer. Therefore, when a function pointer is dereferenced, it is (with some exceptions) immediately turned back into a pointer to function.
References
n1570 (the final public draft of the current C standard):
6.5.3.2 Address and indirection operators
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; [...]
...
6.3.2.1 Lvalues, arrays, and function designators
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.
6.5.2.2 Function calls 5
If the expression that denotes the called function has type pointer to
function returning an object type, the function call expression has
the same type as that object type, and has the value determined as
specified in 6.8.6.4.
I'm relatively new to C, and found it intriguing that both of the following calls to the function pointer compile and work fine. One with and one without dereferencing the function pointer before calling it.
#include <stdio.h>
#include <stdlib.h>
void func() {
puts("I'm a func");
}
int main(void) {
void (*f)() = func;
f();
(*f)();
return EXIT_SUCCESS;
}
I think I understand that (*f)() is the "official" way to call a function pointer, but why does simply calling f() work? Is that syntactic sugar of recent C versions?
This is a piece of syntactic/semantic sugar that has, AFAIK, worked since the very earliest versions of C. It makes sense if you think of functions as pointers to code.
The only special rule needed to make function pointers work this way is that indirecting a function pointer gives the same pointer back (because you can't manipulate code in standard C anyway): when f is a function pointer, then f == (*f) == (**f), etc.
(Aside: watch out with declaration such as void (*f)(). An empty argument list denotes an old-style, pre-C89 function declaration that matches on the return type only. Prefer void (*f)(void) for type safety.)
A function call expression is always of the form "function pointer", "round parenthesis", "arguments", "round parenthesis". In order for you not to have to spell out (&printf)("Hello World\n") every time1, there is a separate rule by which an expression which denotes a function decays to the respective function pointer.
Since a function pointer can be dereferenced to give an expression that denotes a function again, this will again decay, so you can keep dereferencing and there'll be a lot of decay:
(&f)(); // no decay (decay does not happen when the expression
// is the operand of &)
f(); // one decay
(*f)(); // two decays
(**f)(); // three decays
1) Early Perl has function syntax like that.
The C 2011 standard says in clause 6.3.2.1, paragraph 4:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.
This means that, if f designates a function, then, in a call such as f(), f is automatically converted to &f, resulting in (&f)(). This is actually the “proper” way to call a function, because the function-call expression requires a pointer to a function.
Now consider what happens in *f. The f is automatically converted to &f, so we have *&f. In this expression, the result of the * operator is a function, f; it just reverse the operation performed by &. So *&f is the same as f. We can repeat this indefinitely: **f is automatically converted to **&f, which is *f, which is automatically converted to *&f, which is f, which is automatically converted to &f.
In C you can call your function like:
f();
(*f)();
(**f)();
(********f)();
(*****************************f)();
all are valid. In C, dereferencing or taking the address of a function just evaluates to a pointer to that function, and dereferencing a function pointer just evaluates back to the function pointer. C is designed in such a way that both function name identifier as well as variable holding function's pointer mean the same: address to CODE memory. And it allows to jump to that memory by using call () syntax either on an identifier or variable.
And the last but but least, standard says that:
C11: 6.3.2.1:
4 A function designator is an expression that has function type. Except when it is the
operand of the sizeof operator, the _Alignof operator,65) or the unary & operator, a
function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.
I found these work types of code:
hash_init.key = &hash_key_lc;
And
ls->handler = init_connection;
Here both hash_key_lc and init_connection are functions,but one is with & the other not,why?
UPDATE
so they are the same thing,but what's the rational??
This is identical to the following question:
In C, what is the difference between `&function` and `function` when passed as arguments?
The accepted answer there:
There is no difference. For evidence
see the C99 specification (section
6.7.5.3.8).
"A declaration of a parameter as
‘‘function returning type’’ shall be
adjusted to ‘‘pointer to function
returning type’’, as in 6.3.2.1."
reference/deference on a function is treated as a language special case in c,as function deserves this kind of special case ,it can't be passed by a certain value,you can only pass it by address/reference.
See C99 section 6.3.2.1, §4:
A function designator is an
expression that has function type.
Except when it is the operand of the
sizeof operator or the unary &
operator, a function designator with
type ‘‘function returning type’’ is
converted to an expression that has
type ‘‘pointer to function returning
type’’.
Thus, if foo is a function, the expressions foo and &foo are mostly interchangeable, in particular
foo == &foo
This is similar to how expressions with array type are implicitly converted to expressions with pointer type. Also, if fp is a function pointer, you can call it with or without dereferencing, ie the expressions
(*fp)(42)
and
fp(42)
are equivalent. Function calls are actually defined in terms of function pointers (section 6.5.2.2 §1) and not function designators, ie as far as language semantics go, *fp in the first example will implicitly converted back to fp before the parens are applied.