Complex C declaration

According to cdecl.org

declare foo as function returning pointer to array SIZE of array SIZE of pointer to function returning pointer to float

Use the spiral rule given by Luchian Grigore if you want to decode it by hand.


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


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();