La règle de type "spirale" ne fait pas partie des règles de priorité suivantes:
T *a[] -- a is an array of pointer to T
T (*a)[] -- a is a pointer to an array of T
T *f() -- f is a function returning a pointer to T
T (*f)() -- f is a pointer to a function returning T
Les opérateurs d’ []
appel d’ indice et de fonction ()
ont une priorité plus élevée que l’unaire *
, ils *f()
sont donc analysés en tant que *(f())
et *a[]
sont analysés en tant que *(a[])
.
Donc, si vous voulez un pointeur vers un tableau ou un pointeur vers une fonction, vous devez regrouper explicitement le *
avec l'identificateur, comme dans (*a)[]
ou (*f)()
.
Ensuite, vous vous en rendez compte a
et il f
peut s'agir d'expressions plus compliquées que de simples identifiants; in T (*a)[N]
, a
pourrait être un simple identifiant, ou un appel de fonction comme (*f())[N]
( a
-> f()
), ou un tableau comme (*p[M])[N]
, ( a
-> p[M]
), ou ce pourrait être un tableau de pointeurs vers des fonctions comme (*(*p[M])())[N]
( a
-> (*p[M])()
), etc.
Ce serait bien si l'opérateur d'indirection *
était postfix au lieu d'unaire, ce qui rendrait les déclarations un peu plus faciles à lire de gauche à droite ( void f[]*()*();
s'écoule certainement mieux que void (*(*f[])())()
), mais ce n'est pas le cas.
Lorsque vous rencontrez une déclaration poilue comme celle-ci, commencez par trouver l' identifiant le plus à gauche et appliquez les règles de priorité ci-dessus, en les appliquant de manière récursive à tous les paramètres de fonction:
f -- f
f[] -- is an array
*f[] -- of pointers ([] has higher precedence than *)
(*f[])() -- to functions
*(*f[])() -- returning pointers
(*(*f[])())() -- to functions
void (*(*f[])())(); -- returning void
La signal
fonction de la bibliothèque standard est probablement le spécimen type de ce genre de folie:
signal -- signal
signal( ) -- is a function with parameters
signal( sig, ) -- sig
signal(int sig, ) -- which is an int and
signal(int sig, func ) -- func
signal(int sig, *func ) -- which is a pointer
signal(int sig, (*func)(int)) -- to a function taking an int
signal(int sig, void (*func)(int)) -- returning void
*signal(int sig, void (*func)(int)) -- returning a pointer
(*signal(int sig, void (*func)(int)))(int) -- to a function taking an int
void (*signal(int sig, void (*func)(int)))(int); -- and returning void
À ce stade, la plupart des gens disent "utiliser des typedefs", ce qui est certainement une option:
typedef void outerfunc(void);
typedef outerfunc *innerfunc(void);
innerfunc *f[N];
Mais...
Comment utiliseriez- vous f
dans une expression? Vous savez que c'est un tableau de pointeurs, mais comment l'utilisez-vous pour exécuter la fonction correcte? Vous devez passer en revue les typedefs et trouver la syntaxe correcte. En revanche, la version "nue" est assez obsédante, mais elle vous indique exactement comment utiliser f
dans une expression (à savoir, (*(*f[i])())();
en supposant qu'aucune des fonctions n'accepte d'arguments).