c陷阱与缺陷第二章——Syntactic Pitfalls
2.1 Understanding function declarations
Every C variable declaration has two parts: a type and a list of expression-like things called declarators.
A declarator looks something like an expression that is expected to evaluate to the given type.
For instance:
float f, g;
indicates that the expressions f
and g
, when evaluated, will be of type float.
Because a declarator looks like an expression, parentheses may be used freely:
float ((f));
means that ((f))
evaluates to a float and therefore, by inference, that f
is also a float.
Analogously,
float *pf;
means that *pf
is a float and therefore that pf
is pointer to a float.
Once we know how to declare a variable of a given type, it is easy to write a cast for that type: just remove the variable name and the semicolon from the declaration and enclose the whole thing in parentheses.
Thus, since
float (*h)();
declares h
to be a pointer to a function returning a float,
(float(*)())
is a cast to a pointer to a function returning a float.
Now we can analyze the following statement:
(*(void(*)())0) ();
First, we can see that
(void(*)())
is a cast to a pointer to function returning void.
So, we cast
0
0
0 to a pointer to function returning void
by saying:
(void(*)())0
and we can replace fp
by (void(*)())0
.
Thus, we can analyze the statement as follows:
(*fp)();
fp
is a pointer to a function returning void, *fp is the function itself, so (*fp)() is the way to invoke it.