This is really a digression, but -
I donât think so. There is only one relevant precedence rule, which is that *a[b] / *a(b) are *(a[b]) and *(a(b)) respectively, not (*a)[b] or (*a)(b). Everything else about type declarations is unambiguously determined from basic syntax principles common to most programming languages.
E.g., why do you write the outer arrayâs size first, then the inner (the âassociativityâ thing Linus mentioned)? Because indexing an array of arrays (outer) gets you one array (inner), and indexing one array gives you the final element. (Some scientific languages have a specific concept of a multidimensional array distinct from an array of arrays, but C joins the norm in not.) Why int *(*x)() for a function pointer returning int *? Because int **x() would call x() and dereference the result (per that rule), while int (**x)() would dereference twice before calling. Et cetera. There is no need to remember some weird âspiral ruleâ or any other rule specific to type declarations; if you remember that one rule of precedence (which you should really know anyway if youâre doing anything with pointers), you should be able to work out any C type by following use.
But you do have to think backwards - work through what sequence of indexes, derefs, and calls you can do to x to eventually get a char, and then flip that around to get an idea of what the type looks like. I can only pin the confusion on this.
Thing is, this âthinking backwardsâ does somewhat resemble whatâs required to understand why *a would be found in a match expression.