Spiral rule and 'declaration follows usage' for parsing C and C++ declarations
You just have to build it up in steps.
char *X(); // X =~ (*(*a[N])())
Function returning char*
char *(*Y())(); // Y =~ (*a[N])
Function returning pointer to function returning char*
.
In a declaration, just as in an expression (declaration follow usage), postfix []
has a higher precedence that unary *
so *a[N]
is equivalent to *(a[N])
, not (*a)[N]
.
char *(*(*Z)())(); // Z =~ a[N]
Pointer to function returning pointer to function returning char*
.
char *(*(*a[N])())();
Array of N pointers to functions returning a pointer to function returning char*
.
Equivalent C declarations
They are not equal. in the first case x
is a pointer to an array of 10 integers, in the second case x
is an array of 10 integers.
The two types are different. You can see they're not the same thing by checking sizeof
in the two cases.
C isn't that hard: void ( *( *f[] ) () ) ()
There is a rule called the "Clockwise/Spiral Rule" to help find the meaning of a complex declaration.
From c-faq:
There are three simple steps to follow:
Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
[X]
or[]
=> Array X size of... or Array undefined size of...
(type1, type2)
=> function passing type1 and type2 returning...
*
=> pointer(s) to...Keep doing this in a spiral/clockwise direction until all tokens have been covered.
Always resolve anything in parenthesis first!
You can check the link above for examples.
Also note that to help you there is also a website called:
http://www.cdecl.org
You can enter a C declaration and it will give its english meaning. For
void (*(*f[])())()
it outputs:
declare f as array of pointer to function returning pointer to function returning void
EDIT:
As pointed out in the comments by Random832, the spiral rule does not address array of arrays and will lead to a wrong result in (most of) those declarations. For example for int **x[1][2];
the spiral rule ignores the fact that []
has higher precedence over *
.
When in front of array of arrays, one can first add explicit parentheses before applying the spiral rule. For example: int **x[1][2];
is the same as int **(x[1][2]);
(also valid C) due to precedence and the spiral rule then correctly reads it as "x is an array 1 of array 2 of pointer to pointer to int" which is the correct english declaration.
Note that this issue has also been covered in this answer by James Kanze (pointed out by haccks in the comments).
Parsing C declarations
First, some basic rules:
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning a pointer to T
T (*f)(); // f is a pointer to a function returning T
const T *p; // p is a non-const pointer to const T
T const *p; // same as above
T * const p; // p is a const pointer to non-const T
In both declarators and expressions, the []
and ()
operators have higher precedence than the *
operator, so you need to explicitly group it with the identifier when working with pointers to arrays ((*a)[N]
) and pointers to functions ((*f)()
).
When you find a hairy declaration, find the left-most identifier and work your way out, remembering the rules above, and applying them recursively to any function parameters:
signal -- signal
signal( ) -- is a function taking
signal( ) -- parameter unnamed
signal(int, ) -- of type int
signal(int, fp ) -- parameter fp
signal(int, (*fp) ) -- is a pointer
signal(int, (*fp)( )) -- to a function taking
signal(int, (*fp)( )) -- parameter unnamed
signal(int, (*fp)(int)) -- of type int
signal(int, void (*fp)(int)) -- returning void
(*signal(int, void (*fp)(int))) -- returning a pointer
(*signal(int, void (*fp)(int)))( ) -- to a function taking
(*signal(int, void (*fp)(int)))( ) -- parameter unnamed
(*signal(int, void (*fp)(int)))(int) -- of type int
void (*signal(int, void (*fp)(int)))(int); -- returning void
In English, signal
is a function that takes an integer and a pointer to a signal function as parameters and returns a pointer to a handling function.
Occasionally you don't have an identifier (as in a function prototype where only the types are specified), so you have to mentally put in a placeholder (call it λ) and apply the rules to that placeholder:
void (*signal(int λ, void (*fp)(int λ)))(int λ);
Get confused with this declaration - int (*(*foo)(double))[3]
You just read from the inside out remembering that postfix array ([]
) and function "call" (()
) bind tighter than prefix pointer (*
):
(*foo) // foo is a pointer...
(*foo)(double) // to a function taking a double...
(*(*foo)(double)) // returning a pointer...
(*(*foo)(double))[3] // to an array of 3...
int (*(*foo)(double))[3]; // ints
(To work out where to start you might want to work from the outside in, but you need to read back from the inside out to read the declaration in the conventional order.)
A way to efficiently parse function pointer declaration syntax
The method I've developed is to start with the leftmost identifier and work out, keeping in mind the following precedence rules:
T *a[N]; // a is an array of pointer
T (*a)[N]; // a is a pointer to an array
T *f(); // f is a function returning a pointer
T (*f)(); // if is a pointer to a function
and doing that recursively for any function parameters.
I'm going to use λ to represent unnamed parameters, so we get something like this:
somename -- somename is
*somename -- a pointer to
(*somename)( ) -- a function taking
(*somename)( λ ) -- unnamed parameter is
(*somename)( *λ ) -- a pointer to
(*somename)( (*λ)()) -- a function taking unspecified parameters
(*somename)(void (*λ)()) -- returning void
*(*somename)(void (*λ)()) -- returning a pointer to
(*(*somename)(void (*λ)()))( ) -- a function taking
(*(*somename)(void (*λ)()))( λ ) -- unnamed parameter is
(*(*somename)(void (*λ)()))( *λ ) -- a pointer to
(*(*somename)(void (*λ)()))( (*λ)()) -- a function taking unspecified parameters
(*(*somename)(void (*λ)()))(void (*λ)()) -- returning void
void (*(*somename)(void (*λ)()))(void (*λ)()); -- returning void
In English, somename
is a pointer to a function that takes a pointer to another function as an argument and returns a pointer yet another function that takes a pointer to a still another function as its argument and returns void
.
Types this obnoxious are rare in the wild, but they do pop up occasionally.
Related Topics
How to Set a Breakpoint in Gdb Where the Function Returns
Mixing C++11 Atomics and Openmp
What Is the <=> ("Spaceship", Three-Way Comparison) Operator in C++
Should I Include <Xxxx.H> or <Cxxxx> in C++ Programs
Why Can't Static_Cast Be Used to Down-Cast When Virtual Inheritance Is Involved
How to Compose Output Streams, So Output Goes Multiple Places at Once
Is the Pointer Guaranteed to Preserve Its Value After 'Delete' in C++
Differencebetween Const_Iterator and Non-Const Iterator in the C++ Stl
When to Use Const and Const Reference in Function Args
Should I Worry About the Alignment During Pointer Casting
How to Get the Hmodule for the Currently Executing Code
Casting Between Void * and a Pointer to Member Function
How to Cin Values into a Vector
How to Find the Size of an Int[]
Number of Combinations (N Choose R) in C++