Sorry in advance if this is really dumb, but I am trying to get my
head around exactly what the declarator is. In the FAQ, 1.21, part of
it says "C declarations ....come in 2 parts, a base type and a
declarator......".
The example used is char *pc where the declarator " *pc" tells us
that " *pc is a character".
Can one thus broadly say that a declarator is in fact equivalent to
the base type?
So, in a more complicated expression eg char * ( *pfpc) () ; once
again "* ( *pfpc) ()" is a character?
Thanks as usual.
Pete and Eric have given you good answers, but I'd like to add a few
things.
The declarator introduces the name of the thing being declared (pc)
and any additional type information not provided by the type specifier
"char". In this case, the "pointerness" of pc is provided by the
declarator *pc.
Remember that in C, declaration mimics use. If I have a pointer to a
character, I retrieve the character value by dereferencing the pointer
like so:
c = *pc;
Thus, the expression "*pc" evaluates to a char value. So, going by
the "declaration mimics use" rule, the declaration for a pointer to
char is
char *pc;
Remember that the '*' is bound to the identifier, not the type
specifier, regardless of any whitespace. "char* pc;" is the same as
"char * pc;" and "char *pc;". If you wrote
char* pc1, pc2;
only pc1 would be declared as a pointer to char; pc2 would be a
regular char.
Array types are similar. If I want to retrieve a specific character
value from an array of char, I use the subscript operator:
c = ac
;
Again, the type of the expression "ac" is char, so the declaration
for an array of char is
char ac[N];
Your function pointer also follows this rule. If I have a pointer to
a function that returns a pointer to a char, I retrieve that char
value by calling that function (using the dereferenced function
pointer), and then dereference the value returned by the function,
like so:
c = *(*pfpc)();
Hence the declaration
char *(*pfpc)();
When you come across a hairier than normal declarator, the way to read
it is to find the leftmost identifier, then work your way out,
remembering that () and [] bind before * (IOW, *a[] is an array of
pointer, not a pointer to an array). Using pfpc as an example:
pfpc -- pfpc
*pfpc -- is a pointer
(*pfpc)() -- to a function
*(*pfpc)() -- returning a pointer
char *(*pfpc)() -- to char.
Note that the type qualifier "typedef" changes things a little. In
the declaration
typedef char *(*pfpc)();
pfpc is not an instance of a pointer to a function to a pointer to
char, but is rather a synonym for the *type* "pointer to a function
returning pointer to char". You could use the typedef to make some
declarations easier to read:
typedef char *charptr; // charptr is a synonym for "char *"
typedef charptr (*fptr)(); // fptr is a synonym for charptr (*)()
fptr myptr; // myptr is a pointer to a function
// returning a pointe to char
although I tend not to do this, as typedefs sometimes obscure more
that they illuminate.