Comment by kazinator

4 hours ago

There is only one iteration through the spiral in any one declarator unless there are parentheses. This is because it's basically:

   [pre] [pre] ... [pre] [core] [post] ... [post]

We have the core of the declarator, usually a name (or empty when omitted). On the left there is a clump of zero or more prefix declarative operators like the pointer *, and on the right postfix ones, like array and function parentheses.

No matter how many there are, you only to around he spiral one time. Let's add the declaration specifiers:

   [spec] ... [spec] [pre] [pre] ... [pre] [core] [post] ... [post]
                                           ------

"We declare "core" to be ..."

  [spec] ... [spec] [pre] [pre] ... [pre] [core] [post] ... [post]
                                          ------      ^
                                             \_______/

                                   

"We declare "core" to be a this, that and other postfix thing ..."

                             ________________________
                             /                        \
  [spec] ... [spec] [pre] [pre] ... [pre] [core] [post] ... [post]
                                           ------      ^
                                              \_______/

"We declare "core"t to be a this, that and other postfix thing, of this pre, pre ...

                              ________________________
                             /                        \
  [spec] ... [spec] [pre] [pre] ... [pre] [core] [post] ... [post]
                  ^________/               ------      ^
                                              \_______/

"We declare "core"t to be a this, that and other postfix thing, of this pre, pre of type/quality given by specs."

For instance:

   const unsigned int * * * x [][][3]
  

"Declare x to be a an array of arrays of arrays of 3 pointers to pointers to pointers, to const unsigned int"

But parentheses override the precedence of postfix versus prefix, so that's when the path follows a spiral with multiple loops, for each nesting level:

    const unsigned int *(*(*x)[][])[3]

Without parentheses, the precedence is as if implicitly there were these parentheses:

    const unsigned int ***(x[][][3])

i.e. postfix "binds tighter" than prefix/unary. That's the whole basis for the spiral: flipping from left to right chasing the sequences of postfix and unary operators, though all the levels of parentheses.

BTW, as a matter of terminology, ISO C does not call type construction punctuators operators; only expressions have operators. In computer science terminology related to programming languages, C declarators are type constructing expressions in which the elements like [] and * are type constructing operators.