Operatori di Assegnamento in Linguaggio C
Una delle operazioni fondamentali in un linguaggio di programmazione è l'assegnamento. Attraverso questa operazione è possibile copiare il valore di un'espressione in una variabile.
In linguaggio C esiste l'operatore di assegnamento semplice =
che permette di assegnare il valore di un'espressione ad una variabile.
Inoltre, per semplificare la scrittura dei programmi, il linguaggio C mette a disposizione anche gli operatori di assegnamento composto +=
, -=
, *=
, /=
e %=
che permettono di assegnare il risultato di un'espressione composta ad una variabile.
In questa lezione vedremo quali sono gli operatori di assegnamento in linguaggio C e come funzionano.
Assegnamento Semplice
L'operatore di assegnamento semplice è il più semplice operatore di assegnamento in linguaggio C. Questo operatore assegna il valore di un'espressione ad una variabile.
int a = 5;
In generale l'operatore di assegnamento semplice ha la seguente sintassi:
v = e;
Quando il flusso di controllo raggiunge l'operatore di assegnamento semplice, viene valutata l'espressione e
. Successivamente il risultato viene copiato all'interno di v
.
L'espressione e
può essere una costante letterale, una variabile oppure un'espressione complessa.
Ad esempio:
x = 4; /* il valore 4 viene copiato in x */
y = x; /* il valore di x viene copiato in y */
z = 3 * x + 2 * y; /* il valore 20 viene copiato in z */
In generale, il linguaggio C impone che l'espressione e
e l'elemento v
abbiano lo stesso tipo. In caso contrario, il compilatore cerca di convertire il valore di e
nel tipo di v
se questo è possibile. Ad esempio:
double x = 3.14;
int y;
y = x; /* y adesso ha il valore 3 */
x = 4; /* x adesso ha il valore 4.0 */
In questo esempio, il compilatore ha convertito il valore di x
da double
a int
quando l'ha copiato in y
. Per cui il valore 3.14 è stato troncato in 3. Successivamente, il compilatore ha convertito il valore di 4
da int
a double
quando l'ha copiato in x
. Queste conversioni sono fatte in automatico dal compilatore in quanto si tratta di valori numerici. Nelle prossime lezioni vedremo come convertire esplicitamente i valori di un tipo ad un altro.
Assegnamento come espressione
In molti linguaggi di programmazione l'assegnamento è un'istruzione, ossia uno statement. In linguaggio C l'assegnamento è un'espressione e pertanto restituisce un valore. Dunque, quando usiamo l'operatore di assegnamento quello che accade è che viene valutata l'espressione e
e il risultato viene copiato in v
. Successivamente, il risultato dell'espressione e
viene restituito come valore dell'operatore di assegnamento.
Dal momento che l'operatore di assegnamento è un'espressione, possiamo usarlo in qualsiasi contesto in cui è possibile usare un'espressione. Ad esempio:
int x;
printf("%d\n", x = 5); /* stampa 5 */
In questo esempio, l'espressione x = 5
viene valutata e restituisce il valore 5. Successivamente, il valore 5 viene passato alla funzione printf
che lo stampa a video.
Possiamo sfruttare questa caratteristica a nostro vantaggio, ad esempio concatenando più assegnamenti:
int x, y, z;
x = y = z = 0; /* tutti i valori vengono inizializzati a 0 */
Tenendo presente che l'operatore di assegnamento è associativo a destra possiamo riscrivere questa espressione in questo modo:
int x, y, z;
x = (y = (z = 0)); /* tutti i valori vengono inizializzati a 0 */
In altre parole, prima viene assegnato il valore 0 alla variabile z
, poi il risultato che è 0 viene assegnato alla variabile y
e infine il risultato, che è sempre 0, viene assegnato alla variabile x
.
Attenzione agli assegnamenti concatenati
Quando si usa la concatenazione di assegnamenti bisogna fare attenzione agli effetti indesiderati.
Ad esempio:
double x;
int y;
x = y = 3.14;
In questo esempio, dapprima il valore 3.14 viene convertito in intero, quindi in 3. Successivamente, viene assegnato alla variabile intera y
. Dopodiché, il valore 3 viene convertito in double e viene assegnato alla variabile double x
.
Quindi il risultato finale è che x
ha il valore 3.0 e non 3.14 come ci si aspetterebbe.
Essendo un'espressione, l'assegnamento può essere utilizzato in qualunque punto di un'altra espressione dove ci si aspetta un valore di quel tipo.
Ad esempio:
int x, y, z;
x = 5;
z = 2 + 3 * (y = x);
Tuttavia è sempre buona norma evitare di mescolare espressioni e assegnamenti in un'unica espressione. Questo perché i programmi diventano più difficili da leggere e da capire.
Introduzione agli Effetti Collaterali
In generale, un operatore effettua un'operazione tra operandi e restituisce un risultato. In matematica, ad esempio, gli operatori di addizione,
Nei linguaggi di programmazione, C incluso, gli operatori, oltre a svolgere le operazioni a cui sono associati, possono modificare gli operandi stessi. Quando ciò accade, si dice che l'operatore ha degli effetti collaterali, dal momento che l'operazione ha effetti che vanno al di là del risultato.
Abbiamo visto che l'operatore di assegnamento semplice, oltre a restituire un risultato, modifica il valore della variabile di destinazione. Dunque, l'operatore di assegnamento semplice ha degli effetti collaterali.
int x, y;
y = 3 * (x = 5);
In tal caso, l'operatore di assegnamento restituisce il valore 5 e modifica l'operando x
.
Effetto Collaterale di un operatore
Un effetto collaterale è la modifica che un operatore applica su uno o più operandi oltre a restituire un risultato.
In realtà, il concetto di effetto collaterale è più generico di quanto scritto sopra. Gli effetti collaterali non si limitano solo alla modifica degli operandi, ma possono riguardare anche la modifica dello stato del programma. Approfondiremo il concetto quando studieremo le funzioni e la visibilità delle variabili.
L-value e R-value
Nella maggior parte dei casi, in linguaggio C, gli operatori agiscono su operandi che possono essere costanti, valori letterali, variabili o altre espressioni.
L'operatore di assegnamento, tuttavia, richiede che uno degli operandi sia qualcosa a cui possa essere assegnato un valore. Questo tipo di entità prende il nome tecnico di l-value.
Il nome l-value deriva proprio dal fatto che sono entità che possono apparire alla sinistra dell'operatore di assegnamento, il nome sta infatti per left-value, ossia valore a sinistra.
L-value
Un l-value è un'entità associata ad una locazione di memoria da cui è possibile leggere dato e in cui è possibile scrivere dati.
Finora, abbiamo incontrato solo un tipo di l-value: le variabili. Per cui, l'operando di sinistra dell'operatore di assegnamento deve essere una variabile.
int x;
x = 5;
Non è possibile assegnare un valore, invece, ad un'espressione:
/* ERRORE */
5 * x = 7;
Espressioni o costanti, infatti, non sono associate a nessuna locazione di memoria, per cui non si può memorizzare nessun valore in esse. Per questo motivo prendono il nome di r-value proprio per il fatto che possono apparire alla destra dell'operatore di assegnamento. Il nome sta infatti per right-value, ossia valore a destra.
R-value
Un r-value è un'entità a cui è associato un risultato, un valore, ma non necessariamente una locazione di memoria.
Un l-value è anche un r-value, ma non sempre vale il contrario.
In base a tale definizione, una costante o un'espressione sono entrambe r-value ma non sono l-value.
Viceversa una variabile può essere sia l-value che r-value. Infatti, una variabile può essere usata come l-value per assegnare un valore ad essa, ma può anche essere usata come r-value per ottenere il valore che essa contiene.
int x;
x = 5; /* x è l-value */
x = x + 1; /* x è r-value */
Assegnamento Composto
Nella scrittura dei programmi, e quindi anche quando si scrive un programma in linguaggio C, sorge spesso l'esigenza di modificare il valore di una variabile calcolando un nuovo valore a partire dal vecchio valore della variabile stessa.
Ad esempio, sorge spesso l'esigenza di incrementare una variabile intera di un valore:
int x;
x = 5;
x = x + 1; /* Incrementa la variabile di 1 */
x = x + 2; /* Incrementa la variabile di 2 */
Dal momento che questo tipo di operazioni si presenta molto spesso nella pratica, il linguaggio C mette a disposizione degli operatori particolari che sintetizzano tali operazioni.
Ad esempio, esiste l'operatore composto di somma e assegnamento che ha la seguente sintassi:
x += e;
L'operatore composto di somma e assegnamento, +=
, esegue la somma tra l'operando x
e l'espressione e
e assegna il nuovo risultato alla variabile x
.
Questo tipo di operatori che combinano un'operazione e l'assegnamento prendono il nome di operatori di assegnamento composti. Di seguito la lista completa:
Operatore | Significato |
---|---|
v += e |
Somma v ed e e memorizza il risultato in v |
v -= e |
Sottrae e a v e memorizza il risultato in v |
v *= e |
Moltiplica e e v e memorizza il risultato in v |
v /= e |
Divide v per e e memorizza il risultato in v |
v %= e |
Calcola il resto della divisione di v per e e memorizza il risultato in v |
Quando si utilizzano gli operatori di assegnamento composti bisogna prestare attenzione alla priorità degli stessi. Infatti l'operatore di assegnamento composto ha una priorità inferiore rispetto agli altri operatori aritmetici.
Ad esempio:
x *= y + 3;
Non equivale a:
(x = x * y) + 3;
Ma equivale a:
x = x * (y + 3);
Inoltre, gli operatori di assegnamento composti sono associativi a destra, per cui la seguente espressione:
x *= y *= z;
equivale a:
x *= (y *= z);
ossia equivale alla sequenza di istruzioni:
y = y * z;
x = x * y;
Attenzione a non invertire i simboli degli operatori di assegnamento composti
Quando si utilizzano gli operatori di assegnamento composto è facile confondersi e invertire i simboli degli operatori. Ad esempio, è facile scrivere:
x =+ 3;
Questa è un'espressione del tutto legale e il compilatore non darà alcun errore. Tuttavia il risultato è che ad x
verrà assegnato il valore +3
, ossia 3
.
In Sintesi
In questa lezione abbiamo imparato dei concetti molto importanti:
- L'operatore di assegnamento
=
assegna il valore di un'espressione ad una variabile; - L'assegnamento è un'espressione il cui risultato è il valore assegnato;
- Gli operatori di assegnamento composto effettuano un'operazione e assegnano il risultato alla variabile;
Questi concetti sono fondamentali nello studio del linguaggio C e li utilizzeremo in tutte le lezioni successive.