I was just going through some code on the Internet and found this:
float * (*(*foo())[SIZE][SIZE])()
How do I read this declaration? Is there a specific set of rules for reading such complex declarations?
A declaration is a C language construct that introduces one or more identifiers into the program and specifies their meaning and properties. Declarations may appear in any scope.
Complicated declarations in C. Redeclaration of global variable in C. Internal Linkage and External Linkage in C. Different ways to declare variable as constant in C and C++ Variable length arguments for Macros.
A "declaration" establishes an association between a particular variable, function, or type and its attributes. Overview of Declarations gives the ANSI syntax for the declaration nonterminal. A declaration also specifies where and when an identifier can be accessed (the "linkage" of an identifier).
I haven't done this in a while!
Start with foo
and go right.
float * (*(*
foo()
)[SIZE][SIZE])()
foo is a function with no arguments...
Can't go right since there's a closing parenthesis. Go left:
float * (*(
* foo()
)[SIZE][SIZE])()
foo is a function with no arguments returning a pointer
Can't go left further, so let's cross the parentheses and go right again
float * (*
(* foo())
[SIZE][SIZE])()
float * (*
(* foo())[SIZE]
[SIZE])()
float * (*
(* foo())[SIZE][SIZE]
)()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE ...
Closing parenthesis reached, left again to reach a pointer symbol:
float * (
*(* foo())[SIZE][SIZE]
)()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to ...
Left parenthesis again, so we cross it and go right again:
float *
( *(* foo())[SIZE][SIZE])
()
float *
( *(* foo())[SIZE][SIZE])()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to a function with no arguments...
And left to the end
float * ( *(* foo())[SIZE][SIZE])()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to a function with no arguments returning a pointer to float
And whoever wrote that, please teach him to use typedef
:
// Function that returns a pointer to float typedef float* PFloatFunc (); // Array of pointers to PFloatFunc functions typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE]; // Function that returns a pointer to a PFloatFuncArray2D PFloatFuncArray2D* foo();
Standard rule: find the leftmost identifier and work your way out, remembering that []
and ()
bind before *
:
foo -- foo foo() -- is a function *foo() -- returning a pointer (*foo())[SIZE] -- to a SIZE-element array (*foo())[SIZE][SIZE] -- of SIZE-element arrays *(*foo())[SIZE][SIZE] -- of pointers (*(*foo())[SIZE][SIZE])() -- to functions * (*(*foo())[SIZE][SIZE])() -- returning pointers float * (*(*foo())[SIZE][SIZE])(); -- to float
So imagine you have a bunch of functions returning pointers to float
:
float *quux(); float *bar(); float *bletch(); float *blurga();
Let's say you want to store them in a 2x2 table:
float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
tab
is a SIZE x SIZE array of pointers to functions returning pointers to float
.
Now let's decide we want a function to return a pointer to that table:
float *(*(*foo())[SIZE][SIZE])() { static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga}; return &tab; }
Note that you could have several functions that build tables of different functions, or organize the same functions differently:
float *(*(*qwerbl())[SIZE][SIZE])() { static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux}; return tab; }
which is the only reason I can think of to do something like this. You shouldn't see types like this in the wild very often (although they do crop up occasionally, and I've been guilty of writing something similarly heinous).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With