Declaration of function pointers

It just is what it is. What exactly is your question? You already seem to understand how all this works.

Commented Mar 12, 2014 at 21:15

When you´re declaring an int, you write the name after ìnt . When declaring a function, the name is between return type and parameters. Same here, name not after the whole stuff, but in the middle. And the name is not foo , but foo(. )

Commented Mar 12, 2014 at 21:18

I suppose typedef char MyArray[10]; rather than typedef char[10] MyArray; also causes you discomfort?

Commented Mar 12, 2014 at 21:20 @WhozCraig: I've been doing C++ for 10 years and yes, that always irks me. Commented Mar 12, 2014 at 21:39

This has always seemed backwards to me too, and I will periodically still have to look it up. I find it slightly strange the response that you are getting here.

Commented Mar 12, 2014 at 21:39

3 Answers 3

An integer is just:

int x; 

A name for the above is given by:

typedef int x_type; 

A pointer to an int is:

int *p; 

It's type would be:

typedef int *p_type; 

A function called foo taking a double``and returning an int` is:

int foo(double); 

Defining the type of foo would be:

typedef int foo_type(double); 

Now a pointer to the above should take an * , but () (function call) binds tighter than * (dereference), so parentesis:

typedef int (*ptr_to_foo_type)(double); 

This might be better written:

typedef foo_type *ptr_to_foo_type; 

as some suggest writing for clarity.

The idea is that the type description looks (somewhat) like its use. Badly mangled idea, given prefix/postfix operators, that much everybody agrees on. But it is now much too late to change.

answered Mar 12, 2014 at 21:24 11.7k 8 8 gold badges 34 34 silver badges 53 53 bronze badges

Declaration syntax is based on the types of expressions, not objects. Another way of saying it is that "declaration mimics use".

Let's start with a simple pointer expression; call it iptr . iptr points to an integer value. If we want to access that value, we need to dereference iptr with the unary * operator, like so:

x = *iptr; 

The expression *iptr has type int , so the declaration of iptr is written

int *iptr; 

If you wanted to create a typedef for an int pointer, you would add the typedef to get

typedef int *iptr; 

iptr now serves as a synonym for type "pointer to int ", so you can write

iptr ip; 

which declares ip as a pointer to int (as a rule, you really don't want to hide pointers in typedefs).

Now let's say you have a pointer to a function that takes two int arguments and returns an int value, call it fp . To call the function, you dereference the pointer and pass the necessary arguments to the resulting function, like so:

x = (*fp)(arg1, arg2); // C allows you to omit the * in the call, so you could // also write it as simply x = fp(arg1, arg2), but we're // leaving it in so the following explanation makes sense 

The function call () operator has higher precedence than unary * ; *fp() will be interpreted as *(fp()) , which is not what we want. To dereference fp before calling the function it points to, we must explcitly group the * operator with fp .

The type of the expression (*fp)(arg1, arg2) is int , so the declaration of fp becomes

int (*fp)(int arg1, int arg2); 

Let's look at your second example now: foo is a function that takes a char argument and returns a pointer to a function that takes an int argument and returns void . You'd call it as something like

(*foo(c))(x); 

Again, the type of the expression (*foo(c))(x) is void , so it follows that the declaration is

void (*foo(char c))(int x); 

For syntactic reasons, typedef is treated as a storage class specifier like extern or static , although it has a very different meaning. It doesn't change the structure of a declaration; it just changes how that declaration is interpreted by the compiler. Adding typedef to the above, as in

typedef void (*foo(char c))(int x); 

now creates the synonym foo for the type "function returning pointer to function returning void ". It's no different from how simpler type definitions like

typedef int *iptr;