Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex C declaration

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?

like image 803
Kaunteya Avatar asked Feb 27 '13 11:02

Kaunteya


People also ask

What is C declaration?

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.

What is complicated declaration and evaluation in C?

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.

What is declaration syntax in C?

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


2 Answers

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(); 
like image 58
Kos Avatar answered Sep 17 '22 15:09

Kos


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

like image 44
John Bode Avatar answered Sep 19 '22 15:09

John Bode