1

In one of the answer to How do function pointers in C work? one user explains how to use function pointers in return values. Here's the code in question:

// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int

int (*functionFactory(int n))(int, int) {
    printf("Got parameter %d", n);
    int (*functionPtr)(int,int) = &addInt;
    return functionPtr;
}

For me the way you declare the functionFactory function is very weird - it seems to me that you mix up the return type (pointer to a function) and the function name itself (functionFactory).

For example, when we write a simple function that returns a square of its argument we write something like

int square(int n){
    return n*n;
}

Clearly, the type of what we return is on the left and then we write the function name and then what parameters it accepts. So when we return a pointer to a function why don't we write something like:

( int (*function)(int, int) ) functionFactory(int n) { ...

Here the return type (which is a pointer to a function) and its details (e.g. what the function that we point to returns and what it accepts as parameters) is clearly on the left separated and the name of the functionFactory function itself is to the right. To me my version seems much more logical and clear, why don't we write it like that?

Community
  • 1
  • 1
  • 1
    C uses infix notation for declarators. This is according to the "declaration follows usage" principle. We access an array as `a[5]`, so it is declared as `int a[5];`, not `int[5] a;`. The same thing is going on with function types. – M.M Nov 10 '16 at 23:34
  • `int (*function)(int, int) functionFactory(int n) { ...` "*Here the return type (which is a pointer to a function)*" - so what's the very first `int` in that line if not the return type? – TessellatingHeckler Nov 10 '16 at 23:35
  • You can of course declare typedefs for these function pointers and then your function declarations using these typedefs will look more "normal". – paddy Nov 11 '16 at 00:29

2 Answers2

2

This falls out of how declarator syntax works. It may help to think in terms of substitution. Here's one way to look it:

T    f   (); // f is a function returning T
     |
     v
T  (*p)  (); // p is a pointer to a function returning T
     |
     v
T  (*q())(); // q is a function returning a pointer to a function returning T

So we start with the function declarator f(). Then we replace f with the pointer (*p), giving us the declarator (*p)(). Finally we replace p with the function q(), giving us the declarator (*q())().

Edit

You may hear people talk about the "spiral rule" when reading hairy declarators. While it's more of a guideline than an actual rule, it falls out of the following precedence rules:

T *a[N];    // a is an array of pointer to T
T (*a)[N];  // a is a pointer to an array of T
T *f();     // f is a function returning T
T (*f)();   // f is a pointer to a function returning T

The postfix [] and () operators have higher precedence than unary *, hence the need for parentheses when declaring pointers to arrays or functions. So when we read T (*q())();, we start from the leftmost identifier q and "spiral" outwards:

    +-----------+
    | +-------+ |
    | | +---+ | |         
    | | |   | | |
    T ( * q ()) ()
      | | | | | |
      | | +-+ | |
      | +-----+ |    
      +---------+

Breaking it down piece by piece:

    q        -- q is a
    q()      -- function returning
   *q()      -- pointer to
  (*q())()   -- function returning
T (*q())();  -- T

You cannot declare arrays of function type, nor can you declare functions to return array types:

T a[N]();    // NOT ALLOWED 
T f()[N];    // NOT ALLOWED 

so in any combination of function and array types, a pointer will always be involved, so the spiral rule holds.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

The following code declares a variable named func to be a pointer to a function that returns an int and takes two ints as parameters:

int (*func)(int, int);

This syntax mimics the syntax how functions are declared in C:

int func(int, int);

See how similar that is? In fact functions in C are just like variables pointing to functions, e.g. see this sample:

int funcA(int a, int b) { ... }
int (*funcB)(int, int) = funcA;

It plays no role through the rest of the code if you call funcA(a,b) or funcB(a,b), does it? So even though funcB is a variable and funcA a function, the truth is, there's a function somewhere in memory and funcA and funcB are both pointers to the address of the function code.

If you want to nitpick, funcA is a constant and funcB is a variable, so the compiler output for a call to funcA will be different than for funcB; also in one case it is a direct call and in one case an indirect call, as the destination of funcB can change over time. This is also what the asterisk is saying, "I'm not a function, I'm a pointer to a function".

It's important to note that in C the asterisk is always next to the variable name to mark that a pointer variable, so how else would you like to write it instead? Like this?

// Careful! Wrong!
int (int, int) *func;

Does that look more readable to you? Or maybe like that?

// Careful! Wrong!
int ()(int, int) *func;

This syntax is not very clear either and it doesn't mimic any other existing C syntax. If you work a lot with function pointers, pass them around and store them in variables, you should declare an own type for your function pointer:

#include  <stdio.h>

int sum ( int a, int b ) {
    return (a + b);
}

typedef int (* MathFuncType)(int, int);

MathFuncType getSumFunc ( ) {
    return &sum;
}

int main(void) {
    MathFuncType func = getSumFunc();
    printf("%d\n", func(3, 8));
    return 0;
}

http://rextester.com/GEKR20461

Mecki
  • 125,244
  • 33
  • 244
  • 253