C/C++ – Dichiarazione Avanzata dei Tipi

Questo articolo prende spunto dal corso di Ingegneria degli Algoritmi e da un articolo di Steve Friedl sulla lettura delle dichiarazione di tipo.

Uno degli scogli principali per chi comincia a programmare in C è proprio quello di comprendere bene il significato dei vari * e delle funzioni più contorte. Non è inverosimile che per i principianti si sviluppi un metodo di programmazzione chiamato “proviamo e vediamo se funziona” che consiste nell’aggiungere asterischi a caso nella dichiarazione fino a quando il programma funziona come sperato.

Ovviamente questo metodo è sconsigliabile, contando che esiste una pratica regola che rende decifrabile anche le dichiarazioni più ingarbugliate: “go right when you can, go left when you must”

In italiano la regola suona più o meno: vai a destra finchè puoi, vai a sinistra quando devi. Ma come tutte le regole necessita di un esempio per essere afferrata.

Prendiamo una dichiarazione che farebbe impazzire chiunque:

char *(*(**foo [][8])())[];

“Oddio!” direte voi, ma manteniamo la calma. Il primo passo consiste nell’isolare il nome della variabile e il tipo base. Il nome della variabile è solitamente l’unica parola non riservata che trovate nella dichiarazione, nel nostro caso foo, mentre il tipo base è il tipo che si trova più a sinistra di tutti.

foo è un ... char

Ora dobbiamo riempire i puntini. Per prima cosa definiamo alcune semplici regole di lettura:

  • gli asterischi * si leggono puntatori a o puntatore a
  • le parentesi quadre [] si leggono array di
  • le parentesi numerate [x] si leggono array di x di
  • le parentesi tonde () si leggono funzione che restituisce
  • le parentesi tonde con parametri (x,y) si leggono funzione che prende come parametro x, y e restituisce

Con queste regole ora non ci resta che partire a seguire la regola principale cominciando dal nome della dichiarazione.

La prima cosa che troviamo andando a destra sono le parentesi quadre, quindi:

char *(*(**foo [][8])())[];

foo è un array di ... char

Continuiamo ad andare a destra (ricordiamoci il “a destra finchè posso”) e troviamo altre parentesi quadre.

char *(*(**foo [][8])())[];

foo è un array di array di 8 di ... char

A questo punto troviamo una parentesi chiusa, non possiamo quindi più andare a destra finchè non troviamo, a sinistra, la corrispondente parentesi aperta. Facciamo quindi un balzo a sinistra e intanto continuiamo a riempire i puntini. A sinistra troviamo due asterischi quindi:

char *(*(**foo [][8])())[];

foo è un array di array di 8 di puntatori a puntatori a ... char

Abbiamo trovato la parentesi. Adesso quindi ci è permesso andare a destra. A destra troviamo un paio di parentesi tonde.

char *(*(**foo [][8])())[];

foo è un array di array di 8 di puntatori a puntatori a funzione che restituisce
... char

Altra parentesi chiusa. Andiamo quindi a sinistra.

char *(*(**foo [][8])())[];

foo è un array di array di 8 di puntatori a puntatori a funzione che restituisce
puntatori a ... char

E cosi via finché non completiamo tutta la dichiarazione.

char *(*(**foo [][8])())[];

foo è un array di array di 8 di puntatori a puntatori a funzione che restituisce 
puntatori a array di... char

E cosi alla fine abbiamo che:

foo è un array di array di 8 di puntatori a puntatori a funzione che restituisce
puntatori a array di puntatori a char.

Abbiamo quindi decriptato con facilità una dichiarazione che sembrava impossibile. Ora, per vedere se avete capito e se siete bravi vi lascio una dichiarazione per esercizio:

int * ( (* (* foo) () ) [5][7]) ()

Buon divertimento! 🙂

Comments are closed.