Texte initialement posté par email sur comp.lang.c par son auteur, David Anderson, le 6/5/1994.
Il existe une technique connue sous le nom de "règle de la spirale horaire" qui permet à tout programmeur C de parser toute déclaration C de tête !
Elle consiste à suivre trois étapes simples :
-
En partant du premier élément inconnu, se déplacer en spirale dans le sens horaire; lorsqu'on rencontre l'élément suivant, le remplacer par son équivalent en langue naturelle :
[X]ou[]→ Tableau de taille X de… ou Tableau de taille indéfinie de…(type1, type2)→ fonction recevant type1 et type2 retournant…*→ pointeur(s) sur… -
Répéter l'étape 1. en spirale, dans le sens horaire, jusqu'à ce que tous les jetons ont été parcourus.
-
Toujours résoudre les parenthèses en premier !
Example #1 : Simple déclaration
┌───────┐
│ ┌─┐ │
│ ▲ │ │
char *str[10];
▲ ▲ │ │
│ └───┘ │
└───────────┘
La question qu'on se pose :
-
Qu'est-ce que
str?strest un… -
On se déplace en spirale horaire commençant par
stret le premier caractère qu'on rencontre est[, il s'agit donc d'un tableau, donc…strest un tableau 10 de… -
Continuons en spirale horaire, et le prochain jeton que nous rencontrons est
*, ce qui signifie que nous avons des pointeurs, donc…strest un tableau 10 de pointeurs sur… -
Toujours en spirale horaire, nous arrivons en fin de ligne (le
;) et nous en continuant nous arrivons sur le typechar, donc…strest un tableau 10 de pointeurs sur char -
Nous avons maintenant "visité" tous les jetons, nous avons donc fini !
Example #2 : Déclaration d'un pointeur sur fonction
┌────────────────────┐
│ ┌───┐ │
│ │┌─┐│ │
│ │▲ ││ │
char *(*fp)( int, float *);
▲ ▲ ▲ ││ │
│ │ └──┘│ │
│ └─────┘ │
└────────────────────────┘
La question qu'on se pose :
-
Qu'est-ce que
fp?fpest un… -
En se déplaçant en spirale horaire, la première chose que l'on voit est
); ce qui signifie quefpest entre parenthèses, nous continuons donc notre spirale à l'intérieur de la parenthèse et le prochain caractère rencontré est*, donc…fpest un pointeur sur… -
Nous sommes désormais hors des parenthèses et continuons en spirale horaire, nous voyons
(, il s'agit d'une fonction donc…fpest un pointeur sur fonction recevant un int et un pointeur sur flottant retournant… -
Toujours en spirale, nous voyons
*, donc…fpest un pointeur sur fonction recevant un int et un pointeur sur flottant retournant un pointeur sur… -
Suivant encore la spirale, nous voyons
;, mais nous n'avons pas encore visité tous les jetons, nous devons continuer et finalement tombons sur char, donc…fpest un pointeur sur fonction recevant un int et un pointeur sur flottant retournant un pointeur sur char.
Exemple #3 : le "Final"
┌─────────────────────────────┐
│ ┌───┐ │
│ ┌───┐ │┌─┐│ │
│ ▲ │ │▲ ││ │
void (*signal(int, void (*fp)(int)))(int);
▲ ▲ │ ▲ ▲ ││ │
│ └──────┘ │ └──┘│ │
│ └────────┘ │
└──────────────────────────────────┘
La question que nous nous posons :
-
Qu'est-ce
signal?Remarquez que
signalest entre parenthèses, nous devons donc les résoudre en premier ! -
En se déplaçant dans le sens horaire, nous voyons
(, nous avons donc…signalest une fonction recevant un int et un… -
Hmmm, nous pouvons appliquer la même règle à
fp, donc… Qu'est-ce quefp?fpest aussi entre parenthèses, donc continuons et nous voyons une*, donc…fpest un pointeur sur… -
Continuons en spirale horaire et nous arrivons à
(, donc…fpest un pointeur sur une fonction recevant un int et retournant… -
Maintenant continous hors des parenthèses de la fonction et nous obtenons
void, donc…fpest un pointeur sur une fonction recevant un int et ne retournant rien (void) -
Fini avec
fp, retournons à notresignal, nous avons maintenant…signalest une fonction recevant un int et un pointeur sur une fonction recevant un int et ne retournant rien retournant… -
Nous sommes encore dans des parenthèses, donc le prochain caractère rencontré est
*, donc…signalest une fonction recevant un int et un pointeur sur une fonction recevant un int et ne retournant rien retournant un pointeur sur… -
Nous avons maintenant résolu tous les jetons présents dans des parenthèses, continuons dans le sens horaire et arrivons à
(, donc…signalest une fonction recevant un int et un pointeur sur une fonction recevant un int et ne retournant rien retournant un pointeur sur une fonction recevant un int et retournant… -
Finalement, nous continuons et la seule chose restante et le mot
void, et donc la définition complète designalest :signalest une fonction recevant un int et un pointeur sur une fonction recevant un int et ne retournant rien retournant un pointeur sur une fonction recevant un int et ne retournant rien (void).
La même règle s'applique à const et volatile. Par exemple :
const char *chptr;
-
Qu'est-ce que
chptr?chptrest un pointeur sur un char constant
Que dites-vous de ça :
char * const chptr;
-
Qu'est-ce que
chptr?chptrest un pointeur constant sur un char
Finalement :
volatile char * const chptr;
-
Qu'est-ce que
chptr?chptrest un pointeur constant sur un char volatile.
Vous pouvez vous entrainer en appliquant cette règle aux exemples du K&R II, page 122.
Copyright © 1993,1994 David Anderson
Traduction © 2013 victor / progdupeu.pl
Cet article peut être librement distribué à condition que les noms des auteurs et cette notice soient conservés. Librement traduit sur la base de cette reproduction du texte original.