It has been said that declaration
s of variable
s, and functions
". This is said rightfully so, as you will see.
Let us take a very simple variable declaration: int a
here is obviously an int
. This seems pretty straight-forward.
Consider a slightly more complex example: int (*a)
is not an int; it is a pointer
. The most
immediate facet of a
is stated immediately next to it.
Let us take next a rather complex example: int (*foo)(double).
What is foo? It is a pointer (the second *).
A pointer to what? It is a pointer to a function
that takes a double for its only argument. What does that
function return? It returns an int.
So, we say that "foo is a pointer to a function (double) that returns an int".
Here's how the cdecl tool explains this to us:
cdecl> explain int (*foo)(double)
declare foo as pointer to function (double) returning int
As you can see, we interpreted it correctly.
Here's a little "trick": When casting to that same type,
you simply remove the "foo" part, and put the whole thing in parentheses:
(int (*(*)(double)))my_void_ptr, where my_void_ptr
is probably of type void *. And, since function prototypes
take nameless arguments, you can do the same thing as a cast, without
no enclosing parentheses.
Anyway, to add to the confusion, we have little shortcut precedences. These
are what let you get away with int *foo instead of int (*foo).
They also allow for slightly confusing types: int *bar. Is that an
array of pointers, or a pointer to an array? Well, the designers of C decided
that array should be "more important" than pointers, so it is the same type as
int (*(bar)). Enter both into cdecl, and you will get
the same explanation.
Now, try to explain this one: int (*quux)(char *(*)(double),int *).
Hint: quux is the variable's name. And no, I can't think of a practical
use for this type.