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
?str
est un… -
On se déplace en spirale horaire commençant par
str
et le premier caractère qu'on rencontre est[
, il s'agit donc d'un tableau, donc…str
est 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…str
est 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…str
est 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
?fp
est un… -
En se déplaçant en spirale horaire, la première chose que l'on voit est
)
; ce qui signifie quefp
est entre parenthèses, nous continuons donc notre spirale à l'intérieur de la parenthèse et le prochain caractère rencontré est*
, donc…fp
est 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…fp
est un pointeur sur fonction recevant un int et un pointeur sur flottant retournant… -
Toujours en spirale, nous voyons
*
, donc…fp
est 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…fp
est 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
signal
est 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…signal
est une fonction recevant un int et un… -
Hmmm, nous pouvons appliquer la même règle à
fp
, donc… Qu'est-ce quefp
?fp
est aussi entre parenthèses, donc continuons et nous voyons une*
, donc…fp
est un pointeur sur… -
Continuons en spirale horaire et nous arrivons à
(
, donc…fp
est un pointeur sur une fonction recevant un int et retournant… -
Maintenant continous hors des parenthèses de la fonction et nous obtenons
void
, donc…fp
est un pointeur sur une fonction recevant un int et ne retournant rien (void) -
Fini avec
fp
, retournons à notresignal
, nous avons maintenant…signal
est 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…signal
est 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…signal
est 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 designal
est :signal
est 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
?chptr
est un pointeur sur un char constant
Que dites-vous de ça :
char * const chptr;
-
Qu'est-ce que
chptr
?chptr
est un pointeur constant sur un char
Finalement :
volatile char * const chptr;
-
Qu'est-ce que
chptr
?chptr
est 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.