Dichiarazioni


Ogni identificatore che il programmatore intende utilizzare in un programma C++, sia esso per una variabile, una costante simbolica, di tipo o di funzione (fanno eccezione le etichette), va dichiarato prima di essere utilizzato. Ci sono diversi motivi che giustificano la necessita` di una dichiarazione; nel caso di variabili, costanti o tipi:

nel caso di funzioni, invece una dichiarazione: Le dichiarazioni hanno anche altri compiti che saranno chiariti in seguito.



Tipi primitivi

Un tipo e` una coppia <V, O>, dove V e` un insieme di valori e O e` un insieme di operazione per la creazione e la manipolazione di elementi di V.
In un linguaggio di programmazione i tipi rappresentano le categorie di informazioni che il linguaggio consente di manipolare. Il C++ fornisce quattro tipi fondamentali: Il tipo char e` utilizzato per rappresentare piccoli interi e caratteri; int e` utilizzato per rapresentare interi in un intervallo piu` grande di char; infine float e double rappresentano entrambi valori in virgola mobile, float per valori in precisione semplice e double per quelli in doppia precisione.
Ai tipi fondamentali e` possibile applicare i qualificatori signed, unsigned, short e long per selezionare differenti intervalli di valori; essi tuttavia non sono liberamente applicabili a tutti i tipi: short si applica solo a int, signed e unsigned solo a char e int e infine long solo a int e double. In definitiva sono disponibili i tipi:
  1. char
  2. short int
  3. int
  4. long int
  5. signed char
  6. signed short int
  7. signed int
  8. signed long int
  9. unsigned char
  10. unsigned short int
  11. unsigned int
  12. unsigned long int
  13. float
  14. double
  15. long double
Il tipo int e` per default signed e quindi e` equivalente al corrispondente tipo signed, invece i tipi char, signed char e unsigned char sono considerate categorie distinte. I vari tipi sopra elencati, oltre a differire per l'intervallo dei valori rappresentabili, differiscono anche per la quantita` di memoria richiesta per rappresentare un valore di quel tipo. Il seguente programma permette di conoscere la dimensione di ciascun tipo come multiplo di char (di solito rappresentato su 8 bit):
#include < iostream.h >

void main() {
   cout << "char = " << sizeof(char) << endl;
   cout << "short int = " << sizeof(short int) << endl;
   cout << "int = " << sizeof(int) << endl;
   cout << "long int = " << sizeof(long int) << endl;
   cout << "signed char = " << sizeof(signed char) << endl;
   cout << "signed short int = " << sizeof(signed short int) << endl;
   cout << "signed int = " << sizeof(signed int) << endl;
   cout << "signed long int = " << sizeof(signed long int) << endl;
   cout << "unsigned char = " << sizeof(unsigned char) << endl;
   cout << "unsigned short int = " << sizeof(unsigned short int) << endl;
   cout << "unsigned int = " << sizeof(unsigned int) << endl;
   cout << "unsigned long int = " << sizeof(unsigned long int) << endl;
   cout << "float = " << sizeof(float) << endl;
   cout << "double = " << sizeof(double) << endl;
   cout << "long double = " << sizeof(long double) << endl;
}
Una veloce spiegazione sul listato:
la prima riga (#include <iostream.h>) richiede l'uso di una libreria per eseguire l'output su video; la libreria iostream.h dichiara l'oggetto cout il cui compito e` quello di visualizzare l'output che gli viene inviato tramite l'operatore di inserimento <<.
L'operatore sizeof(<Tipo>) restituisce la dimensione di Tipo, mentre endl inserisce un ritorno a capo e forza la visualizzazione dell'output. Infine main e` il nome che identifica la funzione principale, ovvero il corpo del programma.
Tra i tipi fondamentali sono definiti gli operatori di conversione, il loro compito e` quello di trasformare un valore di un tipo in un valore di un altro tipo. Non esamineremo per adesso l'argomento, esso verra` ripreso in una apposita appendice.



Variabili e costanti

Siamo ora in grado di dichiarare variabili e costanti. La sintassi per la dichiarazione delle variabili e`
    < Tipo > < Lista Di Identificatori > ;
Ad esempio:
    int a, b, B, c;
    signed char Pippo;
    unsigned short Pluto;         // se ommesso si intende int
Innanzi tutto ricordo che il C++ e` case sensitive, cioe` distingue le lettere maiuscole da quelle minuscole, infine si noti il punto e virgola che segue sempre ogni dichiarazione.
La prima riga dichiara quattro variabili di tipo int, mentre la seconda una di tipo signed char. La terza dichiarazione e` un po' particolare in quanto apparentemente manca la keyword int, in realta` poiche` il default e` proprio int essa puo` essere ommessa; in conclusione la terza dichiarazione introduce una variabile di tipo unsigned short int. Gli identificatori che seguono il tipo sono i nomi delle variabili, se piu` di un nome viene specificato essi devono essere separati da una virgola.
E` possibile specificare un valore con cui inizializzare ciascuna variabile facendo seguire il nome dall'operatore di assegnamento = e da un valore o una espressione che produca un valore del corrispondente tipo:
    int a = -5, b = 3+7, B = 2, c = 1;
    signed char Pippo = 'a';
    unsigned short Pluto = 3;
Se nessun valore iniziale viene specificato, il compilatore inizializza le variabili con 0.
La dichiarazione delle costanti e` identica a quella delle variabili eccetto che deve sempre essere specificato un valore e la dichiarazione inizia con la keyword const:
    const a = 5, c = -3;     // int e` sottointeso
    const unsigned char d = 'a', f = 1;
    const float = 1.3;


Scope e lifetime

La dichiarazione di una variabile o di un qualsiasi altro identificatore si estende dal punto immediatamente successivo la dichiarazione (e prima dell'eventuale inizializzazione) fino alla fine del blocco di istruzioni in cui e` inserita (un blocco di istruzioni e` racchiuso sempre tra una coppia di parentesi graffe). Cio` vuol dire che quella dichiarazione non e` visibile all'esterno di quel blocco, mentre e` visibile in eventuali blocchi annidati dentro quello dove la variabile e` dichiarata. Il seguente schema chiarisce la situazione:
                    // Qui X non e` visibile
    {
    ...             // Qui X non e` visibile
    int X = 5;      // Da ora in poi esiste una variabile X
    ...             // X e` visibile gia` prima di =
      {             // X e` visibile anche in questo blocco
      ...
      }
    ...
    }               // X ora non e` piu` visibile
All'interno di uno stesso blocco non e` possibile dichiarare piu` volte lo stesso identificatore, ma e` possibile ridichiararlo in un blocco annidato; in tal caso la nuova dichiarazione nasconde quella piu` esterna che ritorna visibile non appena si esce dal blocco ove l'identificatore viene ridichiarato:
    {
    ...                      // qui X non e` ancora visibile
    int X = 5;
    ...                      // qui e` visibile int X
      {
      ...                    // qui e` visibile int X
      char X = 'a';          // ora e` visibile char X
      ...                    // qui e` visibile char X
      }                      // qui e` visibile int X
    ...
    }                        // X ora non piu` visibile
All'uscita dal blocco piu` interno l'identificatore ridichiarato assume il valore che aveva prima di essere ridichiarato:
    {
      ...
      int X = 5;
      cout << X << endl;         // stampa 5
      while (--X) {              // riferisce a int X
        cout << X << ' ';        // stampa int X
        char X = '-';
        cout << X << ' ';        // ora stampa char X
      }
      cout << X << endl;         // stampa di nuovo int X
    }
Una dichiarazione eseguita fuori da ogni blocco introduce un identificatore globale a cui ci si puo` riferire anche con la notazione ::<ID>. Ad esempio:
    int X = 4;        // dichiarazione esterna ad ogni blocco

    void main() {
      int X = -5, y = 0;
      /* ... */
      y = ::X;        // a y viene assegnato 4
      y = X;          // assegna il valore -5
    }
Abbiamo appena visto che per assegnare un valore ad una variabile si usa lo stesso metodo con cui la si inizializza quando viene dichiarata. L'operatore :: e` detto risolutore di scope e, utilizzato nel modo appena visto, permette di riferirsi alla dichiarazione globale di un identificatore.
Ogni variabile oltre a possedere uno scope, ha anche un propria durata (lifetime), viene creata subito dopo la dichiarazione (e prima dell'inizializzazione! ndr) e viene distrutta alla fine del blocco dove e` posta la dichiarazione; fanno eccezione le variabili globali che vengono distrutte alla fine dell'esecuzione del programma. Da cio` si deduce che le variabili locali (ovvero quelle dichiarate all'interno di un blocco) vengono create ogni volta che si giunge alla dichiarazione, e distrutte ogni volta che si esce dal blocco; e` tuttavia possibile evitare che una variabile locale (dette anche automatiche) venga distrutta all'uscita dal blocco facendo precedere la dichiarazione dalla keyword static:
    void func() {
      int x = 5;                // x e` creata e distrutta ogni volta
      static int c = 3;         // c si comporta in modo diverso
      /* ... */
    }
La variabile x viene creata e inizializzata a 5 ogni volta che func() viene eseguita, e viene distrutta alla fine dell'esecuzione della funzione; la variabile c invece viene creata e inizializzata una sola volta, quando la funzione viene chiamata la prima volta, e distrutta solo alla fine del programma. Le variabili statiche conservano sempre l'ultimo valore che viene assegnato ad esse e servono per realizzare funzioni il cui comportamento e` legato a computazioni precedenti (all'interno della stessa esecuzione del programma). Infine la keyword static non modifica lo scope.


Pagina precedente - Pagina successiva



C++, una panoramica sul linguaggio - © Copyright 1997, Paolo Marotta