I'm having trouble with the following syntax in C:
float (*func(unsigned id))(float value) {
...
}
I understand that:
func
func
accepts one argument of type unsigned
called id
func
returns a pointer to a function that looks like: float f(float value)
But I don't understand why the return value of f
(the returned function pointer) is separated from its argument list.
Also, is: func(unsigned id)
an expression that evaluates to some pointer? Is this the reason why (*func(unsigned id))
works?
Can someone clarify this syntax step by step?
The expression func(id)
returns a pointer to a function that takes a float as argument and returns a float.
float(*f)(float v); // pointer to a function
float val;
f = func(3); // returns a pointer to a function
val = (*f)(3.14); // calls the function pointed to with argument 3.14
Of course, you could rewrite the last statement:
val = (*func(3))(3.14); // take the ptr returned by func(3) and call the function pointed to.
If you have a function like:
float fct1 (float v) { return 2.0f*v+3.1f; }
you could write:
f = fct1; // reassign the pointer to function f to the adress of fct1
Let's look at the syntax. The C11 standard (draft N1570) states in 6.5.2.2 point 1: that "The expression that denotes the called function) shall have type pointer to function" and in point 3 that: "A postfix expression followed by parentheses () containing a possibly empty, comma-separated list of expressions is a function call."
This covers of course the usual cases:
val = fct1 (3.14); // fct1 is the function designator which adresses the function
val = (*f) (3.14); // (*f) the dereferenced function pointer, so it addresses the function
But the following is also valid according to standard:
val = f(3.14); // This works as well, because f is a pointer to a function
val = func(3)(3.14) // works also because func(3) is a pointer to a function
However first expression is ambiguous for the human reader, who might think of f as a function designator, expecting it to be defined somewhere. And the second is unusual as well. Furthermore, earlier versions of C didn't recognize them. My K&R edition for 1978 required the form (*f)() to call a function pointer.
A last syntactic remark: If you would define f as float *f (float);
it wouldn't be understood as a pointer to a function, but as a forward declaration of a plain function called f and returning a pointer to float. Why ? Because the C precedence rules give ()
a higer precedence than *
meaning that the compiler would understand it as (float *)(f(float))
. This is why an explicit parenthesis is required to show that (*f)
is the function pointer.