-2
int (*(*var[3])())(void (*)());

How would you describe the type of var in the above declaration?

I get:

Declares var as array of 3 pointers to functions (A)

  • These functions (A) take any inputs and return a pointer to a function (B)

  • These functions (B) take a pointer to a function (C) and return int

  • These functions (C) take any inputs and return nothing

Is this right? Thanks

Codo
  • 75,595
  • 17
  • 168
  • 206
Jamila
  • 3
  • 1
  • 1
    remember remember the Clockwise/Spiral rule: http://c-faq.com/decl/spiral.anderson.html – Samer Tufail Sep 06 '16 at 11:57
  • `declare var as array 3 of function returning pointer to function (pointer to function returning void) returning int` http://cdecl.org/ – Hatted Rooster Sep 06 '16 at 11:57
  • 6
    *How would you describe the type of var in the above declaration?* I'd say it's confusingly bad code. Any time you have to ask "What does this mean?" it's **bad code**. If you *need* this kind of construct, that's what `typedef` is for. – Andrew Henle Sep 06 '16 at 11:58
  • thanks for the help – Jamila Sep 06 '16 at 12:00
  • @AndrewHenle: I saw questions asking "what does `int a[10]` mean. Would that also qualify as bad code? I agree there is some point a declaration is too complicated and should be split into multiple `typedef`s (and that one above definitively is such a candidate), but similar to splitting code into functions there is fixed line. – too honest for this site Sep 06 '16 at 13:00
  • @AndrewHenle: The only really *bad* thing about this declarator is the unspecified parameter lists; if the functions take no parameters, then that should be spelled out with `void`. Otherwise, it's not *that* bad. – John Bode Sep 06 '16 at 14:06

1 Answers1

3

Start with the leftmost identifier and work your way out, remembering that () and [] bind before *, so:

T *a[N]      // a is an array of pointer to T
T (*a)[N]    // a is a pointer to an array of T
T *f()       // f is a function returning pointer to T
T (*f)()     // f is a pointer to a function returning T

Edit

Although it doesn't show up in this declaration, const can introduce its own share of wrinkles:

T const *p   // p is a pointer to constant T
const T *p   // same as above

In both of these cases, p points to a constant T. You can write to p (make it point to a different object), but you cannot write to *p (you cannot update the value of the thing p points to).

T * const p  // p is a constant pointer to T

This declares p as a constant pointer to T; You can write to *p (update the value of the thing p points to, assuming *p results in a modifiable lvalue), but you cannot write to p (you can't make it point to a different object).

End edit

So

        var                      -- var is a
        var[3]                   -- 3-element array of
       *var[3]                   -- pointer to
      (*var[3])()                -- function taking 
      (*var[3])()                --   unspecified parameters 
     *(*var[3])()                -- returning pointer to
    (*(*var[3])())(          )   -- function taking
    (*(*var[3])())(          )   --   unnamed parameter is a
    (*(*var[3])())(      *   )   --   pointer to
    (*(*var[3])())(     (*)())   --   function taking
    (*(*var[3])())(     (*)())   --     unspecified parameters
    (*(*var[3])())(void (*)())   --   returning void
int (*(*var[3])())(void (*)());  -- returning int

So, var is a 3-element array of pointers to functions, each of which returns a pointer to another function (which takes a pointer to yet another function as an argument) that returns int.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • On a not so serious note, `var` can also be described as containing (at least) 3 reasons for your colleagues to slap you on the wrists, an unspecified amount of incomprehensible runtime access violations waiting to happen, and an implied `"I quit!"` string literal. Just because you can, doesn't mean you should. – sendaran Sep 06 '16 at 13:14
  • @sendaran: There are valid use cases for tables of function pointers; granted, a table of pointers to functions taking pointers to functions is stretching it, though. – John Bode Sep 06 '16 at 15:37
  • Of course, function pointer tables are my preferred solution for replacing cumbersome switch-case FSMs and similar value to action mappings. Sometimes, like the current example, things go over board and your intention is lost in cryptic syntax. Then you need to calm down and rethink your life choices. Personally, I consider using function pointers without a `typedef` just plain evil. Without syntactic sugar code can become bitter. – sendaran Sep 07 '16 at 06:43