Can someone explain why "void func_dec(void (*)(int) funcptr);" is illegal - c

When declaring a functions which takes function pointer as argument as mentioned below the compiler throws error.
void func_dec(int x, void(*)() funcptr);
Whereas it accepts below declaration,
void func_dec(int x, void(*funcptr)());
Why the compiler could not recognize the former declaration though it looks logical.

It is illegal because the formal definition in the language standard says so. As for the reason why it is that way, and it really may seem obscure, here it is:
From The New C Standard: An Economic and Cultural Commentary (v 1.2 from June 24, 2009, section 6.7 Declarations):
The intent of this syntax is for an identifier’s declarator to have
the same visual appearance as an instance of that identifier in an
expression. For instance, in:
int x[3], *y, z(void);
char (*f(int))[];
the identifier x might appear in the source as an indexed
array, y as a dereferenced pointer, and z as a function call. An
example of an expression using the result of a call to f is
(*f(42))[1].
And the same from The Development of the C Language by Dennis M. Ritchie:
Thus,
int i, *pi, **ppi;
declare an integer, a pointer to an integer, a
pointer to a pointer to an integer. The syntax of these declarations
reflects the observation that i, *pi, and **ppi all yield an int type
when used in an expression. Similarly,
int f(), *f(), (*f)();
declare
a function returning an integer, a function returning a pointer to an
integer, a pointer to a function returning an integer;
int *api[10], (*pai)[10];
declare an array of pointers to integers, and a pointer to
an array of integers. In all these cases the declaration of a variable
resembles its usage in an expression whose type is the one named at
the head of the declaration.

This is because,
void(*)() funcptr
is in invalid syntax on it's own.
Just supply the type while writing the function declaration,
void func_dec(int , void(*) ());
it should be enough. Otherwise, if you want to specify the variable name also, write
void func_dec(int x, void(*funcptr) ());

The function parameter name should go in the same place as the function name goes when you declare a function.
Function declaration:
void func(); // correct syntax
void() func; // incorrrect syntax
Function pointer declaration:
void (*func_ptr)(); // correct syntax
void (*)() func_ptr; // incorrect syntax
Declaring a function pointer becomes easier if you use the following trick:
Take the function declaration. Replace the function name with (*pointerName), or (*) if you want an unnamed version.
Example:
int func1(char* parm1); // function
int (*func1_ptr)(char* parm1); // function pointer
// function taking a function pointer as parameter:
void foo(int (*func1_ptr)(char*));
// The same declaration with an unnamed parameter:
void foo(int (*)(char*));

Related

In C, can you omit the parameter types of a function pointer when initializing it with the address of a declared function?

I'm trying to make sure I understand the syntax for function pointers in C. I know it's just a pointer to a specific type. That being said, why does the following code compile and print '10'?
(Note I'm using GCC 9.4.0 on Ubuntu 20.04)
void f(int);
void (*foo)() = f;
int main(){
foo(10);
return 0;
}
void f(int n){
printf("%d\n", n);
}
Shouldn't we at least get a compile time warning: initialization of 'void(*)()' with incompatible pointer type 'void(*)(int)'? Is foo getting initialized to void(*)(int) based on f?
If I change 'void f(int)' to 'void f(float)' I do get a warning. If I add 3 more int params to f e.g. void f(int, int, int, int) it still compiles and runs fine. If I make the last param a float, another warning.
The rules are the same for function pointer declarations as for function declarations ; and a pointer to function with empty parentheses parameter list is compatible with a pointer to prototyped function, if the return type matches.
In your example the issues are equivalent to:
void g();
int main()
{
g(10);
}
void g(int) { ..... }
The rules are: you can declare a function with empty parentheses and call it with arguments, but in the function call, certain conditions must be met and it is undefined behaviour with no diagnostic required if those conditions are not met.
One of the "certain conditions" is that you cannot have float as a parameter type in the function definition. Another is that the type and count of arguments must match the type and count of parameters in the function definition. To repeat, no diagnostic is required for any of this; your compiler is going above minimum requirements by warning about the incorrect parameter type float.
The type of the function pointer foo:
void (*foo)()
Is a pointer to a function taking an unspecified number of parameters and returning void. So a pointer to any function that has a return type of void (assuming no parameters are subject to promotion, i.e. char, short, float) is compatible with foo and can be assigned to it.
If you instead defined it like this:
void (*foo)(void)
This would generate an error for an incompatible pointer type, as foo points to a function that takes no arguments and returns void, and f does not match that.

The void type in C

The void type in C seems to be strange from various different situations. Sometimes it behaves like a normal object type, such as int or char, and sometimes it just means nothing (as it should).
Look at my snippet. First of all, it seems strange that you can declare a void object, meaning you just declare nothing.
Then I created an int variable and casted its result to void, discarding it:
If an expression of any other type is evaluated as a void
expression, its value or designator is discarded. (ISO/IEC 9899:201x, 6.3.2.2 void)
I tried to call my function with a void cast, but my compiler gave me (Clang 10.0):
error: too many arguments to function call, expected 0, have 1
So the void in a prototype means nothing, and not the type void.
But then, I created a pointer to void, dereferenced it, and assigning the “result” to my int variable. I got the “incompatible type” error. That means the void type does exist here.
extern void a; // Why is this authorised ???
void foo(void); // This function takes no argument. Not the 'void' type.
int main(void)
{
int a = 42;
void *p;
// Expression result casted to 'void' which discards it (per the C standard).
(void)a;
// Casting to 'void' should make the argument inexistant too...
foo((void)a);
// Assigning to 'int' from incompatible type 'void': so the 'void' type does exists...
a = *p;
// Am I not passing the 'void' type ?
foo(*p);
return 0;
}
Is void an actual type, or a keyword to means nothing ? Because sometimes it behaves like the instruction “nothing is allowed here”, and sometimes like an actual type.
EDIT: This questions is NOT a duplicate. It is a purely about the semantics of the void type. I do not want any explanation about how to use void, pointers to void or any other things. I want an answer per the C standard.
In C language the void type has been introduced with the meaning of 'don't care' more than 'null' or 'nothing', and it's used for different scopes.
The void keyword can reference a void type, a reference to void, a void expression, a void operand or a void function. It also explicitly defines a function having no parameters.
Let's have a look at some of them.
The void type
First of all void object exists and have some special properties, as stated in ISO/IEC 9899:2017, §6.2.5 Types:
The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
Pointers
The more useful reference to void, or void *, is a reference to an incomplete type, but itself is well defined, and then is a complete type, have a size, and can be used as any other standard variable as stated in ISO/IEC 9899:2017, §6.2.5 Types:
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements.
All pointers to structure types shall have the same representation and alignment requirements as each other.
All pointers to union types shall have the same representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Casting to void
It can be used as cast to nullify an expression, but allowing the completion of any side effect of such expression. This concept is explained in the standard at ISO/IEC 9899:2017, §6.3 Conversions, §6.3.2.2 void:
The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression.
If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
A practical example for the casting to void is its use to prevent warning for unused parameters in function definition:
int fn(int a, int b)
{
(void)b; //This will flag the parameter b as used
... //Your code is here
return 0;
}
The snippet above shows the standard practice used to mute compiler warnings. The cast to void of parameter b acts as an effective expression that don't generate code and marks b as used preventing compiler complains.
void Functions
The paragraph §6.3.2.2 void of the standard, covers also some explanation about void functions, that are such functions that don't return any value usable in an expression, but functions are called anyway to implement side effects.
void pointers properties
As we said before, pointers to void are much more useful because they allow to handle objects references in a generic way due to their property explained in ISO/IEC 9899:2017, §6.3.2.3 Pointers:
A pointer to void may be converted to or from a pointer to any object type.
A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
As practical example imagine a function returning a pointer to different objects depending on input parameters:
enum
{
FAMILY, //Software family as integer
VERSION, //Software version as float
NAME //Software release name as char string
} eRelease;
void *GetSoftwareInfo(eRelease par)
{
static const int iFamily = 1;
static const float fVersion = 2.0;
static const *char szName = "Rel2 Toaster";
switch(par)
{
case FAMILY:
return &iFamily;
case VERSION:
return &fVersion;
case NAME:
return szName;
}
return NULL;
}
In this snippet you can return a generic pointer that can be dependent on input par value.
void as functions parameter
The use of void parameter in functions definitions was introduced after the, so called, ANSI-Standard, to effectively disambiguate functions having variable number of arguments from functions having no arguments.
From standard ISO/IEC 9899:2017, 6.7.6.3 Function declarators (including prototypes):
The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
Actual compilers still support function declaration with empty parenthesis for backward compatibility, but this is an obsolete feature that will eventually be removed in future release of standard. See Future directions - §6.11.6 Function declarators:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent
feature.
Consider the following example:
int foo(); //prototype of variable arguments function (backward compatibility)
int bar(void); //prototype of no arguments function
int a = foo(2); //Allowed
int b = foo(); //Allowed
int c = bar(); //Allowed
int d = bar(1); //Error!
Now resembling your test, if we call the function bar as follows:
int a = 1;
bar((void)a);
Triggers an error, because casting to void an object doesn't null it. So you are still trying to pass a void object as parameter to a function that don't have any.
Side effects
As requested this is a short explain for side effects concept.
A side effect is whichever alteration of objects and values derived from the execution of a statement, and which are not the direct expected effect.
int a = 0;
(void)b = ++a;
In the snippet above the void expression lose the direct effect, assigning b, but as side effect increase the value of a.
The only reference, explaining the meaning, in the standard can be found in 5.1.2.3 Program execution:
Accessing a volatile object, modifying an object, modifying a
file, or calling a function that does any of those operations are all
side effects, which are changes in the state of the execution
environment.
Evaluation of an expression in general includes both value
computations and initiation of side effects.
void is a type. Per C 2018 6.2.5 19, the type has no values (the set of values it can represent is empty), it is incomplete (its size is unknown), and it cannot be completed (its size cannot be known).
Regarding extern void a;, this does not define an object. It declares an identifier. If a were used in an expression (except as part of a sizeof or _Alignof operator), there would have to be a definition for it somewhere in the program. Since there cannot a definition of void object in strictly conforming C, a cannot be used in an expression. So I think this declaration is allowed in strictly conforming C but is not useful. It might be used in C implementations as an extension that allows getting the address of an object whose type is not known. (For example, define an actual object a in one module, then declare it as extern void a; in another module and use &a there to get its address.)
The declaration of functions with (void) as a parameter list is a kludge. Ideally, () might be used to indicate a function takes no parameters, as is the case in C++. However, due to the history of C, () was used to mean an unspecified parameter list, so something else had to be invented to mean no parameters. So (void) was adopted for that. Thus, (void) is an exception to the rules that would say (int) is for a function taking an int, (double) is for a function taking a double, and so on—(void) is a special case meaning that a function takes no parameters, not that it takes a void.
In foo((void) a), the cast does not make the value “not exist.” It converts a to the type void. The result is an expression of type void. That expression “exists,” but it has no value and cannot be used in an expression, so using it in foo((void) a) results in an error message.
From C Standard#6.2.5p19:
19 The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
This indicate that the void type exists.
Doubt 1:
void foo(void); // This function takes no argument. Not the 'void' type.
Correct.
From C Standard#6.7.6.3p10 [emphasis mine]:
10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
This is a special case they had to add to the language syntax because void foo(); already meant something different (void foo(); doesn't specify anything about foo's parameters). If it weren't for the old meaning of void foo();, void foo(); would have been the syntax to declare a no-argument function. You can't generalize anything from this. It's just a special case.
Doubt 2:
// Casting to 'void' should make the argument inexistant too...
foo((void)a);
No, it will not because void is also an object type though it is incomplete.
Doubt 3:
// Assigning to 'int' from incompatible type 'void': so the 'void' type does exists...
a = *p;
Yes, it does exist and hence the compiler is reporting error on this statement.
Doubt 4:
// Am I not passing the 'void' type ?
foo(*p);
Declaration of foo() function:
void foo(void);
^^^^
The void in parameter list indicates that function will not take any argument because it has been declared with no parameters.
Just for reference, check this from C Standard#5.1.2.2.1p1 [emphasis mine]:
1 The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
^^^^
Doubt 5:
extern void a; // Why is this authorised ???
This is authorized because void is a valid type and it is just a declaration. No storage will allocate to a.
In C, void can't be considered as a data type, it is a keyword used as a placeholder in place of a data type to show that actually there is no data. Hence this
void a;
is not valid.
while here
void foo(void);
void keyword is used to inform to the compiler that foo is not going to take any input argument nor it has return type.
In below case
int a = 42;
void *p;
a = *p; /* this causes error */
a = *p; is wrong because you can't dereference void pointer directly, you need to perform proper type casting first. for e.g
a = *(int*)p; /* first typecast and then do dereference */
Also this
foo(*p);
is wrong because of two reason,
firstly foo() doesn't expects any argument.
secondly you can't do *p as p is void pointer. Correct one is foo(*(int*)p); if foo() declaration is void foo(int);.
Note that this
(void)a;
doesn't do anything so your compiler might not giving any warning but when you do like
int b = (void)a;
compiler won't allow as void is not consider as data type.
Finally this
extern void a; // Why is this authorised ???
this is just a declaration not definition, a doesn't exist until you define it, since a is having extern storage class, you need to define somewhere & when you are going define like
a = 10;
compiler throws a error as
error: ‘a’ has an incomplete type
From C standard 6.2.5 Types
The void type comprises an empty set of values; it is an
incomplete object type that cannot be completed.
6.3.2.2 void
The (nonexistent) value of a void expression (an expression that has
type void) shall not be used in any way, and implicit or explicit
conversions (except to void) shall not be applied to such an
expression. If an expression of any other type is evaluated as a
void expression, its value or designator is discarded. (A void
expression is evaluated for its side effects.)
6.3.2.3 Pointers
A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
A storage-class specifier or type qualifier modifies the keyword
void as a function parameter type list (6.7.6.3).
An attempt is made to use the value of a void expression, or an
implicit or explicit conversion (except to void) is applied to a
void expression (6.3.2.2).
First of all, it seems strange that you can declare a void object, meaning you just declare nothing.
void is an incomplete object type that cannot be completed. This mostly defines its uses in regular contexts, i.e. contexts that do not provide special treatment for void. Your extern declaration is one of such regular contexts. It is OK to use an incomplete data type in a non-defining declaration.
However, you will never be able to provide a matching definition for that declaration.
So the void in a prototype means nothing, and not the type void.
Correct. The parameter must be unnnamed. And the (void) combination is given special treatment: it is not one parameter of type void, but rather no parameters at all.
But then, I created a pointer to void, dereferenced it, and assigning the “result” to my int variable. I got the “incompatible type” error. That means the void type does exist here.
No. It is illegal to apply unary * operator to a void * pointer. Your code is invalid for that reason already. Your compiler issued a misleading diagnostic message. Formally, diagnostic messages are not required to properly describe the root of the problem. The compiler could've just said "Hi!".
Is void an actual type, or a keyword to means nothing ?
It is a type. It is an incomplete object type that cannot be completed.

Aren't a[][] and (*a)[] equivalent as function parameters?

Function prototype
void foo(int n, int a[][]);
gives error about incomplete type while
void foo(int n, int (*a)[]);
compiles. As per the decay rule int a[][] is equivalent to int (*a)[] in this case and therefore int (*a)[] should also give an error about an incomplete type but GCC seems to accept it. Is there anything I am missing?
This might be a GCC bug but I didn't find anything related to it.
No, they are not equivalent as function parameters. They are not equivalent in exactly the same way as parameter declarations in foo and bar
struct S;
void foo(struct S* s); // OK
void bar(struct S a[]); // ERROR: incomplete type is not allowed
are not equivalent.
C does not allow incomplete types as array elements (see C 1999 6.7.5.2/1: "[...] The element type shall not be an incomplete or function type. [...]") and this restriction applies to array parameter declarations the same way as it applies to any other array declarations. Even though parameters of array type will be later implicitly adjusted to pointer type, C simply provides no special treatment for array declarations in function parameter lists. In other words, array parameter declarations are checked for validity before the aforementioned adjustment.
Your int a[][] is the same thing: an attempt to declare an array with elements of type int [], which is an incomplete type. Meanwhile, int (*a)[] is perfectly legal - there's nothing unusual about pointers to incomplete types.
As a side note, C++ "fixed" this issue, allowing arrays of incomplete type in parameter declarations. However, the original C++ still prohibits int a[][] parameters, int (&a)[] parameters and even int (*a)[] parameters. This was supposedly fixed/allowed later in C++17 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#393)
An incomplete type is allowed in contexts where the size doesn't need to be known.
With this declaration:
int a[][]
It is invalid even as a function parameter because the size of one array dimension is needed to know how to perform pointer arithmetic on the second dimension.
This however is valid:
int (*a)[];
Because the size of the array doesn't need to be known in order to use a pointer to it.
Section 6.2.7 of the C standard gives an example of a declaration like this:
5 EXAMPLE Given the following two file scope declarations:
int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]);
The resulting composite type for the function is:
int f(int (*)(char *), double (*)[3]);
This example shows a declaration of type double (*)[3] that is compatible with a declaration of type double (*)[]
You can't however directly use this like a 2D array because of the missing size. Here are some examples to illustrate. If you attempt to do this:
void foo(int n, int (*a)[])
{
int i,j;
for (i=0;i<n;i++) {
for (j=0;j<n;j++) {
printf("a[%d][%d]=%d\n",i,j,a[i][j]);
}
}
}
The compiler (as expected) tells you this:
error: invalid use of array with unspecified bounds
printf("a[%d][%d]=%d\n",i,j,a[i][j]);
^
You can get around this by taking advantage of the fact that an array, even of indeterminate size, decays to a pointer in most contexts:
#include <stdio.h>
void foo(int n, int (*a)[])
{
int i,j;
for (i=0;i<n;i++) {
// dereference "a", type is int[], which decays to int *
// now manually add "n" ints times the row
int *b = *a + (n*i);
for (j=0;j<n;j++) {
printf("a[%d][%d]=%d\n",i,j,b[j]);
}
}
}
int main()
{
int a[2][2] = { {4,5},{6,7} };
foo(2,a);
return 0;
}
This compiles clean with the following output:
a[0][0]=4
a[0][1]=5
a[1][0]=6
a[1][1]=7
Even outside of a function, the int (*)[] syntax can be used:
#include <stdio.h>
int main()
{
int a[2][2] = { {4,5},{6,7} };
int i,j,n=2;
int (*aa)[];
// "a" decays from int[2][2] to int (*)[2], assigned to int (*)[]
aa = a;
for (i=0;i<n;i++) {
int *b = *aa + (n*i);
for (j=0;j<n;j++) {
printf("a[%d][%d]=%d\n",i,j,b[j]);
}
}
return 0;
}
EDIT
Having read through all the relevant parts of the standard, C11 6.7.6.2 and 6.7.6.3, I believe this is a compiler bug/non-conformance. it apparently boils down to the text that the committee sneaked into the middle of a paragraph concerning array delimiters. 6.7.6.2/1 emphasis mine:
In addition to optional type qualifiers and the keyword static, the [
and ] may delimit an expression or *. If they delimit an expression
(which specifies the size of an array), the expression shall have an
integer type. If the expression is a constant expression, it shall
have a value greater than zero. The element type shall not be an
incomplete or function type. The optional type qualifiers and the
keyword static shall appear only in a declaration of a function
parameter with an array type, and then only in the outermost array
type derivation.
Now this is of course very poorly written, basically it says
"peripheral feature of little interest, peripheral feature of little
interest, peripheral feature of little interest, OUT OF THE BLUE HERE COMES SOME ARRAY ELEMENT TYPE SPECIFICATION NOT RELATED TO THE REST OF THIS PARAGRAPH, peripheral feature of little interest, peripheral feature
of little interest,...."
So it is easy to misunderstand, fooled me.
Meaning that int a[][] is always incorrect no matter where it is declared, since an array cannot be an array of incomplete type.
However, my original answer below raises some valid concerns regarding whether array decay should be done before or after the compiler decides if the type is incomplete or not.
Given the specific case void foo(int n, int a[][]); only, this is a function declaration. It is not a definition.
C11 6.7.6.3/12
If the function declarator is not part of a definition of that
function, parameters may have incomplete type
So first of all, parameters are allowed to have incomplete type in the function declaration. The standard is clear. Which is why code like this compiles just fine:
struct s; // incomplete type
void foo(int n, struct s a); // just fine, incomplete type is allowed in the declaration
Furthermore:
C11 6.7.6.3/4
After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.
After adjustment is very important here.
Meaning that after adjusting int a[][] to int (*a)[], the parameter shall not have incomplete type. It does not, it is a pointer to incomplete type, which is always allowed and perfectly fine.
The compiler is not allowed to first evaluate int a[][] as an incomplete array of incomplete arrays, and then later adjust it (if it found that the type was not incomplete). This would directly violate 6.7.6.3/4.

Declaration of function pointers

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?
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.
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.
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.

What is "int *(*pfp) ();" doing in C?

What does this do?
int *(*pfp) ();
int *(*pfp) ();
Creates a pointer to a function that returns int*. The function pointer name ispfp.
Here's an example:
int* myFunc(void)
{
return NULL;
}
int main(int argc, char**argv)
{
int *(*pfp) (void);
pfp = myFunc;
return 0;
}
Note: Since the parameters of the function pointer is not (void) that you gave, that means that the parameter list is not specified in C. In C++ it would mean that it's a function with no parameters exactly.
Brian's explained the "what", but if you're curious as to the why, here's an excerpt from Dennis Ritchie's The Development of the C Language:
The second innovation that most clearly distinguishes C from its predecessors is this fuller type structure and especially its expression in the syntax of declarations. NB offered the basic types int and char, together with arrays of them, and pointers to them, but no further ways of composition. Generalization was required: given an object of any type, it should be possible to describe a new object that gathers several into an array, yields it from a function, or is a pointer to it.
For each object of such a composed type, there was already a way to mention the underlying object: index the array, call the function, use the indirection operator on the pointer. Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax in which the names typically appear. Thus,
int i, *pi, **ppi;
declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used in an expression. Similarly,
int f(), *f(), (*f)();
declare a function returning an integer, a function returning a pointer to an integer, a pointer to a function returning an integer;
int *api[10], (*pai)[10];
declare an array of pointers to integers, and a pointer to an array of integers. In all these cases the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration.
For more info, read Steve Friedl's "Reading C type declarations" or Eric Giguere's "Reading C Declarations: A Guide for the Mystified".
pfp is a pointer to a function that takes no parameters (or indeterminate parameters in C) and returns a pointer to an int.
Using the 'clockwise-spiral' rule is an effective way to decipher complex C declarations (at least I find it effective):
http://c-faq.com/decl/spiral.anderson.html
Use http://www.cdecl.org/ for these things, if you're not sure.

Resources