Reputation: 6762
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
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
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
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 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.
Upvotes: 4
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