cfunctionpointerssyntaxfunction-pointers

Function that returns a function pointer syntax


I'm having trouble with the following syntax in C:

float (*func(unsigned id))(float value) {
    ...
}

I understand that:

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?


Solution

  • 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.