Complex C declaration

C++CFunction PointersDeclaration

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

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

Solution 3 - C++

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.

Solution 4 - C++

The best thing to do here is convert to a series of typedefs.

typedef float * fnReturningPointerToFloat();
typedef fnReturningPointerToFloat* fnArray[SIZE][SIZE];
fnArray* foo();

Solution 5 - C++

Generally, you could try cdecl.org but you'd need to substitute for SIZE

Say you swap SIZE for 12, you'd get:

> declare foo as function returning pointer to array 12 of array 12 of > pointer to function returning pointer to float

I'm not sure that really helps you!

Two observations here:

  1. I'm guessing that this code didn't have a comment beside it explaining what the purpose of it was (i.e. not the technical explanation of what it is but what it is achieving from a functional / business perspective) If a programmer needs to use something as complex as this, they should be good enough to explain to future maintainers what purpose it serves.
  2. Certainly in C++ there are more obvious and probably safer ways of achieving the same thing.

Solution 6 - C++

This document gaves me the best clue about how to easily ready any C declaration :

http://c-faq.com/decl/spiral.anderson.html

> 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!

Example :

		     +-------+
		     | +-+   |
		     | ^ |   |
		char *str[10];
		 ^   ^   |   |
		 |   +---+   |
		 +-----------+

Question we ask ourselves: What is str?

``str is an...

- We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
  ``str is an array 10 of...

- Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
  ``str is an array 10 of pointers to...

- Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''

We have now ``visited'' every token; therefore we are done!

Solution 7 - C++

Although most of the answers above are good enough, there is a lack of complete set of rules for decoding complex C declarations. I have provided a complete set below to decode any complex C declaration. This set of rules is actually based on the precedence of operators. Rules such as right hand spiral rules can be thought of as a shortcut for these set of rules.

Before anything else we need to know a few things to decode the declaration.

'Basic Type' of a declaration

A C declaration always has only one basic declaration type. This is at the left most position of a declaration. For example -

  • int a - basic type is 'int'
  • float *p - basic type is 'float'
  • char (*p)[3] - basic type is 'char'

Precedence and associativity

Next we need to know the precedence order of (), [], and * - dereference operator

  1. (), [] - Associativity is left to right
  2. * - Associativity is right to left

Phrase corresponding to each of the operator above

Next we need to know the decoded phrase corresponding to each operator. Examples ahead will make this point clear.

  • () - function returning
  • [SIZE] - array of SIZE
  • * - pointer to

Now follow the rules below to decode the declaration

  1. Always write the variable name first followed by an 'is'.

    For example -

  • int a - a is ...
  • float *p - p is ...
  • char (*p)[3] - p is ...
  1. Always end with basic type

    For example -

  • int a - a is ... int
  • float *p - p is ... float
  • char (*p)[3] - p is ... char
  1. Now fill the part in between using the following sub-steps

    • Starting from the name, follow the operator precedence and associativity to choose next highest priority operator and append the phrase corresponding to it to the middle part of the decoded string.

    • Repeat the sub step above for the remaining declaration until the decoding process is complete

NOTE 1: For simplicity, I have ignored the arguments of the function however it can be included just after the phrase corresponding to ().

NOTE 2: Parenthesis(()) change the priority order of operators, just like in any arithmetic expression.

NOTE 3: You can use parenthesis in the decoded declaration to increase readability( I have done it in some examples below). Think of each set of () as a single unit.

NOTE 4: A n dimensional array is actually an array of array of ... (n-1 times) array. For ex - int A[2][3] - A is array of 2 (array of 3 int) i.e A is an array of 2 elements in which each element is an array containing 3 integers

Examples

  • int a - a is int
  • float *p - p is pointer to float
  • char (*p)[3] - p is pointer to array of 3 char

Some complex declaration examples

  1. int **p[10] - p is array of 10 pointer to pointer to int
  2. int (*p)[10] - p is pointer to array of 10 int
  3. int *p(char *a) - p is function returning pointer to int
  4. int (*p(char*a))[10] - p is function returning (pointer to (array of 10 int))
  5. int *(*p)() - p is pointer to (function returning (pointer to int))
  6. int (*p()[20])[10] - p is function returning (array of 20 (pointer to (array of 10 int)))

This set of rules can be used with const as well - const qualifier modifies the term to the left of it (if present) otherwise it modifies the term to the right of it.

  1. const int *p[10] - p is array of 10 pointer to int const
  2. int const *p[10] - p is array of 10 pointer to const int (this is same as 7th example)
  3. int *const p[10] - p is array of 10 const pointer to int

Now a really complex example which will not find its use anywhere in practice but nevertheless can be used to demonstrate the decoding process

  1. char *(*(**foo[][8])())[] - foo is array of (array of 8 (pointer to (pointer to (function returning (pointer to (array of (pointer to char)))))))

Now at last decoding for the declaration given in the question

float * (*(*foo())[SIZE][SIZE])() - foo is function returning (pointer to (array of SIZE (array of SIZE (pointer to (function returning pointer to float)))))

The following is the link for the article from which I read this decoding process

Example 10 has been taken from this article

http://www.unixwiz.net/techtips/reading-cdecl.html

Solution 8 - C++

from http://cdecl.org/

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKaunteyaView Question on Stackoverflow
Solution 1 - C++KosView Answer on Stackoverflow
Solution 2 - C++John BodeView Answer on Stackoverflow
Solution 3 - C++Clement J.View Answer on Stackoverflow
Solution 4 - C++QuentinUKView Answer on Stackoverflow
Solution 5 - C++Component 10View Answer on Stackoverflow
Solution 6 - C++Maël NisonView Answer on Stackoverflow
Solution 7 - C++AbhiView Answer on Stackoverflow
Solution 8 - C++David RanieriView Answer on Stackoverflow