10
void (*func)(int(*[ ])());
warren
  • 32,620
  • 21
  • 85
  • 124
arunachalam
  • 1,889
  • 3
  • 13
  • 6
  • See http://stackoverflow.com/questions/1448849/how-to-understand-complicated-function-declarations – pmg Nov 06 '09 at 13:10

6 Answers6

31

The general procedure for reading hairy declarators is to find the leftmost identifier and work your way out, remembering that [] and () bind before * (i.e., *a[] is an array of pointer, not a pointer to an array). This case is made a little more difficult by the lack of an identifier in the parameter list, but again, [] binds before *, so we know that *[] indicates an array of poitners.

So, given

void (*func)(int(*[ ])());

we break it down as follows:

       func                   -- func
      *func                   -- is a pointer
     (*func)(           )     -- to a function taking
     (*func)(     [ ]   )     --    an array
     (*func)(    *[ ]   )     --    of pointers
     (*func)(   (*[ ])())     --    to functions taking 
                              --      an unspecified number of parameters
     (*func)(int(*[ ])())     --    returning int
void (*func)(int(*[ ])());    -- and returning void

What this would look like in practice would be something like the following:

/**
 * Define the functions that will be part of the function array
 */
int foo() { int i; ...; return i; }
int bar() { int j; ...; return j; }
int baz() { int k; ...; return k; }
/**
 * Define a function that takes the array of pointers to functions
 */
void blurga(int (*fa[])())
{
  int i;
  int x;
  for (i = 0; fa[i] != NULL; i++)
  {
    x = fa[i](); /* or x = (*fa[i])(); */
    ...
  }
}    
...
/**
 * Declare and initialize an array of pointers to functions returning int
 */
int (*funcArray[])() = {foo, bar, baz, NULL};
/**
 * Declare our function pointer
 */
void (*func)(int(*[ ])());
/**
 * Assign the function pointer
 */
func = blurga;
/**
 * Call the function "blurga" through the function pointer "func"
 */
func(funcArray); /* or (*func)(funcArray); */
John Bode
  • 119,563
  • 19
  • 122
  • 198
20

It's not a statement, it's a declaration.

It declares func as a pointer to a function returning void and taking a single argument of type int (*[])(), which itself is a pointer to a pointer to a function returning int and taking a fixed but unspecified number of arguments.


cdecl output for ye of little faith:

cdecl> explain void (*f)(int(*[ ])());
declare f as pointer to function (array of pointer to function returning int) returning void
caf
  • 233,326
  • 40
  • 323
  • 462
  • "fixed but unspecified number of arguments" - the question is also tagged C++, in which case that second function type takes precisely zero arguments. – Steve Jessop Nov 06 '09 at 13:26
  • 3
    The C++ tag was added by someone other than the original poster, after I'd answered. A move too-clever-by-half, by my book. – caf Nov 06 '09 at 13:27
  • Gosh, that is sneaky. It's never clear when someone says "C/C++" whether they've said it because they think the answer is the same for both languages, because they think the answers is different between the two... – Steve Jessop Nov 06 '09 at 13:51
  • +1, i just wanna explain why you say "pointer to pointer" and cdecl says "array of pointer": this is because in functions, parameters declared as arrays become pointers. Just so no-one says "hey, you have a typo" :) – Johannes Schaub - litb Nov 06 '09 at 15:37
5

Yes:

$ cdecl
explain void (* x)(int (*[])());
declare x as pointer to function 
  (array of pointer to function returning int) returning void
2

void (*func)(blah); is a pointer to a function taking blah as an argument, where blah itself is int(*[ ])() is an array of function pointers.

Wernsey
  • 5,411
  • 22
  • 38
2

Here's a guide on reading C declarations:

http://www.ericgiguere.com/articles/reading-c-declarations.html

maxyfc
  • 11,167
  • 7
  • 37
  • 46
2

Geordi is a C++ bot, allowing to train this:

<litb> geordi: {} void (*func)(int(*[ ])());
<litb> geordi: -r << ETYPE_DESC(func)
<geordi> lvalue pointer to a function taking a pointer to a pointer to a nullary function 
         returning an integer and returning nothing

It can do many useful things, like showing all parameter-declarations (this, in fact, is just matching raw C++ grammar rule names):

<litb> geordi: show parameter-declarations
<geordi> `int(*[ ])()`.

Let's do it in the opposite direction:

<litb> geordi: {} int func;
<litb> geordi: make func a pointer to function returning void and taking array of pointer to 
       functions returning int
<litb> geordi: show
<geordi> {} void (* func)(int(*[])());

It executes anything you give to it, if you ask it. If you are trained but just forgot some of the scary parentheses rules, you may also mix C++ and geordi-style type descriptions:

<litb> geordi: make func a (function returning void and taking (int(*)()) []) *
<geordi> {} void (* func)(int(*[])());

Have fun!

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212