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.

Nota

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.

Effetti Collaterali

In generale, un operatore effettua un'operazione tra operandi e restituisce un risultato. In matematica, ad esempio, gli operatori di addizione, +, e sottrazione, -, combinano due operandi e danno un risultato.

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.

Definizione

Effetto Collaterale

Un effetto collaterale è la modifica che un operatore applica su uno o più operandi oltre a restituire un risultato.

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.

Definizione

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.

Definizione

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
Tabella 1: Operatori di assegnamento composti in linguaggio C

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;
Nota

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.