Xufeng
Xufeng

Reputation: 6762

Declaration of function pointers

  1. To declare a function pointer using typedef, it will be something like:

    typedef void (*FOO)(int i)

    But normally the syntax for typedef is like:

    typedef int BOOL

    so why is the first one not:

    typedef void (*)(int) FOO

  2. To return a function pointer (without typedef), the syntax is as follow:

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

    which means foo takes in a char and returns a pointer to a function which takes an int and returns nothing. The syntax is so weird! It looks like foo takes in an int and returns nothing. The parentheses don't seem to be in the right places. If it is to return a function pointer, why is it not something like:

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

    which is very straightforward. I am really having trouble understanding the syntax here, let alone using it. Can someone please explain what's going on here?

Upvotes: 3

Views: 977

Answers (3)

John Bode
John Bode

Reputation: 123448

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;

behave.

Upvotes: 2

vonbrand
vonbrand

Reputation: 11791

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 anint` 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.

Upvotes: 4

keshlam
keshlam

Reputation: 8058

1) The syntax for typedef is to take a declaration of a variable of that type and put typedef in front of it.

2) The syntax for declarations echos the syntax for actually obtaining a value of that type. See my other recent answers regarding precedence of addressing operators (including function call), such as (*twod)[3] vs *(twod)[3] C Pointers ... I'd rather not repeat it all again.

Upvotes: 0

Related Questions