Guida Linguaggio C: Le Costanti, i Tipi, le Variabili
18 Novembre 2007 C
   





Introduzione

Un identificatore è un nome che viene associato a diverse entità come costanti, tipi, variabili, funzioni, ecc. e serve ad identificare la particolare entità. L'identificatore sarà poi sostituito dall'indirizzo della variabile o della costante o della funzione.
Gli identificatori in C devono soddisfare determinati vincoli. Un identificatore deve iniziare con un carattere o con il simbolo '_' (underline), e può contenere solo lettere, numeri e il simbolo underline.

Esempio
  1. int a, _a, a2; // identificatore corretto
  2.  
  3. char 2b; //identificatore non corretto
  4.  


Le Costanti

Una costante è un identificatore a cui è associato un valore che resterà fisso per tutta la durata dell'esecuzione del programma. A differenza di una variabile, il cui valore può variare più volte durante l'esecuzione del programma la costante mantiene inalterato il suo valore.
Vi sono due modi per dichiarare una costante: utilizzare la const o utilizzare la direttiva al preprocessore define. Nel primo caso si associa all'identificatore il valore, la costante viene vista come una variabile con un valore fisso, nel secondo caso il compilatore andrà a sostituire, in fase di compilazione, a tutte le occorrenze dell'identificatore il valore associato.
In sostanza, definendo una costante tramite la const il compilatore farà sì (inserirà del codice) che in fase di esecuzione vi sarà una locazione di memoria relativa alla costante in cui sarà presente il valore associato alla costante. Definendo una costante tramite la define il compilatore sostituirà a tutte le occorrenze dell'identificatore il valore associato, in questo modo non vi sarà alcuna locazione di memoria associata alla costante ed il valore sarà inserito direttamente all'interno del codice.
La definizione di costante, tramite la const, avrà la seguente forma

  1. const tipo id = valore;

dopo la parola chiave const si indicherà il tipo della costante, l'identificatore e quindi il valore.

Esempio
Alcuni esempi di dichiarazioni di costanti sono le seguenti

  1. const int a = 1;
  2. const char b = 'a';
  3.  
  4. const char c[] = "Stringa";
  5. const char d[] = {'S', 't', 'r', 'i', 'n', 'g', 'a'};
  6.  
  7. const int e[] = {1, 2, 3};
  8. const int e2[3] = {1, 2, 3};
  9. const int e3[3] = {1, 2};
  10.  
  11. const int f[][2] = {{1, 2}, {3, 4}, {5, 6}};
  12. const int f2[3][2] = {{1, 2}, {3, 4}, {5, 6}};
  13.  
  14. const int g = 23; //numero 23 in decimale
  15. const int h = 027; //numero 23 in ottale
  16. const int i = 0x17; //numero 23 in esadecimale
  17.  
  18. const float k = 23.47;
  19. const float l = 2.347e1;

Le prime due dichiarazioni di costanti sono banali dichiarazioni di un intero e di un carattere. Da notare come un carattere viene indicato tra apice singolo ('a').
Particolarmente interessante è vedere come viene dichiarato un array di caratteri. In C il tipo stringa non esiste, a differenza del C++, quindi le stringhe vengono gestite tramite gli array di caratteri.
Una costante stringa può essere dichiarata in due modi, come indicato in riga 4, indicando la stringa per esteso racchiusa tra doppi apici, oppure come in riga 5, carattere per carattere ciascuno racchiuso tra apici singolo. Nel primo caso il compilatore di assegnare correttamente il valore alla costante.
Da notare inoltre che in quelle dichiarazioni non si è inserita la dimensione dell'array. Non è necessario, sarà sempre il compilatore a sistemare le cose.
Un array di costanti può essere dichiarato in due modi, specificando, come in riga 8, o non specificando, come in riga 7, la dimensione dell'array. Tutti gli elementi dell'array sono racchiusi tra parentesi graffe e ciascun elemento è separato da una virgola.
Tutti gli elementi non specificati nella definizione di array di costanti intere, come in riga 9, sono automaticamente fissati a 0. Nell'esempio in riga 9 l'array e3 sarà costituito dai seguenti elementi: 1 e 2, specificati, e 0, non specificato.
Una matrice di costanti può essere dichiarata specificando, come in riga 11, o non specificando, come in riga 10, la dimensione dell'array esterno. Tutti gli elementi dell'array sono racchiusi tra parentesi graffe e ciascun elemento è separato da una virgola. In questo caso ciascun elemento è a sua volta un array, quindi l'elemento sarà costituito da elementi racchiusi tra parentesi graffe e separati dalle virgole.
Un numero intero può essere espresso in decimale, binario, ottale ed esadecimale. Un numero con lo 0 come prima cifra è interpretato come un numero espresso in base ottale, un numero con il prefisso "0x" o "0X" è interpretato come un numero espresso in base esadecimale, un numero con
Un costante reale può essere definita in due modi, usando solo la parte intera e la parte frazionaria, come in riga 18, o usando la notazione esponenziale, come in riga 19.

La definizione di costante, tramite la define, avrà la seguente forma

  1. #define id valore

dopo la direttiva define si indicherà l'identificatore della costante e quindi il valore.

Esempio
  1. #define a 12
  2.  

I Tipi Predefiniti

In C i tipi predefiniti sono descritti nella tabella che segue, il range dei tipi numerici è definito dalle macro definite nel file limits.h e nel file float.h.

Tipi Predefiniti in C
Tipo Descrizione
Intero unsigned short int Può rappresentare un numero intero compreso tra 0 e il valore della macro USHRT_MAX definita in limits.h.
In genere USHRT_MAX=65535 e variabili di questo tipo occupano 2 byte.
Intero unsigned int Può rappresentare un numero intero compreso tra 0 ed il valore della macro UINT_MAX definita in limits.h.
Il valore di UINT_MAX può variare da una macchina all'altra. Può avere la stessa dimensione di uno short int su una macchina e la stessa dimensione di un long int su un'altra macchina.
In genere può essere UINT_MAX=65535, o UINT_MAX=4294967295.
Intero unsigned long int Può rappresentare un numero intero compreso tra 0 ed il valore della macro ULONG_MAX definita in limits.h.
In genere può essere ULONG_MAX=4294967295.
Intero signed short int ovvero short int Può rappresentare un numero intero compreso tra i valori delle macro SHRT_MIN e SHRT_MAX definite in limits.h.
In genere SHRT_MIN=-32768, SHRT_MAX=32767, e variabili di questo tipo occupano 2 byte.
Intero signed int ovvero int Può rappresentare un numero intero compreso tra i valori delle macro INT_MIN e INT_MAX definite in limits.h.
Il valore di INT_MIN e INT_MAX può variare da una macchina all'altra. Può avere la stessa dimensione di uno short int su una macchina e la stessa dimensione di un long int su un'altra macchina.
In genere può essere INT_MIN=-32768 e INT_MAX=32767, o INT_MIN=-2147483648 e INT_MAX=2147483647.
Intero signed long int ovvero long int Può rappresentare un numero intero compreso tra i valori delle macro LONG_MIN e LONG_MAX definite in limits.h.
In genere LONG_MIN=-2147483648, LONG_MAX=2147483647, e variabili di questo tipo occupano 4 byte.
Carattere unsigned char Può rappresentare un carattere il cui codice è tra 0 ed il valore della macro UCHAR_MAX definita in limits.h.
In genere può essere UCHAR_MAX=255, e variabili di questo tipo occupano 1 byte.
Carattere signed char ovvero char Può rappresentare un carattere il cui codice è tra i valori delle macro SCHAR_MIN e SCHAR_MAX definite in limits.h.
In genere SCHAR_MIN=-128, SCHAR_MAX=127, e variabili di questo tipo occupano 1 byte.
Reale float Può rappresentare un numero reale in singola precisione compreso tra i valori delle macro FLT_MIN e FLT_MAX definite in float.h. In genere FLT_MIN=-1038, FLT_MAX=1038, e le variabili di questo tipo occupano 4 byte.
Reale double Può rappresentare un numero reale in doppia precisione compreso tra i valori delle macro DBL_MIN e DBL_MAX definite in float.h. In genere DBL_MIN=-10308, DBL_MAX=10308, e le variabili di questo tipo occupano 6 byte.
Reale long double Può rappresentare un numero reale in doppia precisione compreso tra i valori delle macro LDBL_MIN e LDBL_MAX definite in float.h. In genere LDBL_MIN=-104932, LDBL_MAX=104932, e le variabili di questo tipo occupano 8 byte.
void Tipo vuoto.



Esempio
Il tipo void può essere usato in diversi contesti. Può essere usato nella defizione di una funzione per indicare che la funzione non restituirà alcun valore

  1. void func()
  2. {
  3. ...
  4. }

o per indicare che la funzione non accetta argomenti

  1. int func(void)
  2. {
  3. ...
  4. }

Si può comunque anche omettere il void, la definizione seguente è uguale alla precedente

  1. int func()
  2. {
  3. ...
  4. }

Si può usare per dichiarare un puntatore generico

  1. void *p;


Tramite la enum è poi possibile definire un tipo di dato enumerativo elencando i valori assumibili da quel tipo di dato. Una variabile di tipo enumerativo può assumere solo i valori appartenenti a questa lista.

Esempio
  1. enum giorno {domenica, lunedi, martedi, mercoledi, giovedi, venerdi, sabato};
  2.  
  3. enum paese {Italia, Francia, Spagna, Germania, Svizzera=10, Inghilterra, Cina};

Nel primo caso viene definito il tipo giorno elencando i valori simbolici che può assumere una variabile di questo tipo. Ad ogni valore simbolico sarà associato un numero intero. Al primo valore simbolico verrà associato il numero 0, al valore simbolico successivo il numero 1, e così via.
Ad un valore simbolico il programmatore può far corrispondere un preciso numero. Nel secondo caso al valore simbolico 'Svizzera' viene fatto corrispondere il numero 10. Il valore simbolico successivo avrà associato il numero 11.
Un tipo di dato enumerativo non può presentare un valore simbolico già presente nella dichiarazione di un altro tipo enumerativo.

  1. enum colori1 {giallo, verde, rosso, marrone, blu};
  2.  
  3. enum colori2 {arancione, grigio, verde, bianco, ciano, magenta};

Nel frammento di codice precedente il valore simbolico verde è presente sia nella dichiarazione di colori1 che in quella di colori2. Questo frammento di codice genererà un errore in fase di compilazione.

I Tipi Strutturati

Array

Un array è una collezione di dati dello stesso tipo. È una struttura costituita da un numero definito di elementi tutti dello stesso tipo.

Figura 1.
Ogni cella dell'array contiene uno di questi elementi. È possibile accedere direttamente, in lettura ed in scrittura, a ciascun elemento (a ciascuna cella) dell'array. Gli elementi di un array possono essere di tipo semplice come interi, caratteri, ecc. o anche di tipo strutturato, come struct. Un array di questo tipo viene chiamato array monodimensionale.
Gli elementi di un array possono anche essere a loro volta degli array. In questo caso ogni cella dell'array conterrà un array. Che a sua volta potrebbe avere come elementi degli array, e così via. Un array di questo tipo viene chiamato array multidimensionale.
Nel caso in cui gli elementi di un array siano degli array monodimensionali l'array viene invece chiamato array bidimensionale o matrice.

Esempio
  1. typedef
  2. {
  3. char cognome[30], nome[30];
  4. int eta;
  5. } persona;
  6.  
  7. persona persone[100];
  8.  
  9. int a[10];
  10.  
  11. int b[] = {0, 1, 2, 3, 4};
  12.  
  13. int matrice[10][5];
  14.  
  15. int multidim[10][10][5];

È possibile definire array di strutture, come nel primo caso, così come array di tipi semplici come interi, caratteri, ecc. Si possono definire subito, al momento della dichiarazione, gli elementi dell'array.
È anche possibile definire matrici, o array multimensionali.

Union

Una union è una collezione di elementi, che possono anche essere di tipo diverso, in cui tutti gli elementi condividono la stessa area di memoria. Questo significa che tutti gli elementi di una union saranno memorizzati nella stessa area di memoria, ed è quindi possibile utilizzare un solo elemento alla volta. Una union può contenere elementi di qualsiasi tipo, quindi la dimensione della union è pari alla dimensione del più grande dei suoi elementi.
Una dichiarazione di union ha la seguente forma

  1. union
  2. {
  3. tipo-elemento elemento1;
  4. tipo-elemento elemento2;
  5. ...
  6. tipo-elemento elementon;
  7. } nome-union;


Esempio
  1. union
  2. {
  3. char cognomenome[50];
  4. int codice;
  5. } persona;

La union persona individua una persona, con nome e cognome o tramite un codice. La dimensione della union è pari alla dimensione del suo elemento più grande. In questo caso la dimensione della union persona è pari alla dimensione dell'array cognomenome.

Strutture

Una struttura è una collezione di elementi, detti membri, anche di tipo diverso. I membri della struttura sono memorizzati in modo sequenziale nell'area di memoria dedicata alla struttura. A differenza della union, quindi, i membri della struttura non condividono la stessa area di memoria. Una dichiarazione di struttura ha la seguente forma

  1. struct
  2. {
  3. tipo-elemento elemento1;
  4. tipo-elemento elemento2;
  5. ...
  6. tipo-elemento elementon;
  7. } nome-struct;


Esempio
  1. struct
  2. {
  3. char cognome[30], nome[30];
  4. int eta;
  5. } persona;

Le Parole Chiave

Per il C sono definite le seguenti parole chiave:
auto const do extern if return static union while
break continue double float int short struct unsigned
case defined else for long signed switch void
char defined enum goto register sizeof typedef volatile
Tutte le parole chiave sono riservate. Non è possibile usare come identificatore una parola chiave.

 
Guida Linguaggio C