Sezione 1.3
Operatori. |
|
|
 |
Una volta appreso dell'esistenza delle variabili e delle costanti possiamo
iniziare ad operare con esse. A questo scopo il C++ fornisce degli operatori,
che nel nostro linguaggio sono un insieme di parole chiave e simboli speciali.
E' importante conoscerli perché essi sono la base del linguaggio
C++.
Non è necessario inparare a memoria tutto il contenuto di questa
sezione. La maggior parte dei dettagli sono riportati per poterli consultare
in seguito qualora se ne abbia bisogno.
-
Assegnamento (=).
-
L'operatore di assegnamento serve per assegnare un valore ad una variabile.
a = 5;
assegna il valore intero 5 alla variabile a
. La parte alla sinistra dell'operatore = è nota come lvalue
(left value) e la parte destra rvalue (right value). lvalue
deve essere sempre una variabile mentre la parte destra può
essere una costante, una variabile, il risultato di una operazione o una
qualsiasi combinazione di essi.
Occorre notare che l'operatore di assegnamento opera sempre da destra
verso sinistra e non nel senso inverso.
a = b;
assegna alla variabile a (lvalue) il valore della
variabile b (rvalue) indipendentemente dal valore
che era precedentemente memorizzato nella variabile a .
Possiamo pensare l'lvalue di a come l'indirizzo
della zona di memoria riservata per memorizzare il valore di a mentre
l'rvalue di b lo dobbiamo pensare come il valore
memorizzato nella zona di memoria riservata per memorizzare il valore
di b. Notiamo inoltre che noi stiamo soltanto assegnando
ad a il valore di b e che una modifica
successiva di b non cambia il nuovo valore di a.
Ad esempio, il seguente codice (in cui è evidenziata in verde
come commento l'evoluzione del contenuto delle variabili):
int a, b; // a:? b:?
a = 10; // a:10 b:?
b = 4; // a:10 b:4
a = b; // a:4 b:4
b = 7; // a:4 b:7
otteniamo alla fine che il valore contenuto in a è
4 e quello contenuto in b è 7.
L'ultima modifica di b non ha modificato a,
benché appena prima avessimo scritto a = b.
Una caratteristica dell'operatore di assegnamento presente in C++ ma
non in altri linguaggi di programmazione è che un assegnamento
si può usare come rvalue (o parte di un rvalue ) in
un altro assegnamento. Ad esempio:
a = 2 + (b = 5);
è equivalente a:
b = 5;
a = 2 + b;
ossia: prima assegna 5 alla variabile b e
poi assegna ad a il valore 2 più
il risultato del precedente assegnamento a b (
5 appunto), ottenendo 7 come valore finale
di a. Quindi, anche la seguente espressione è
valida in C++:
a = b = c = 5;
assegna 5 a tutte e tre le variabili a,
b e c.
-
Operatori aritmetici ( +, -, *, /, % )
-
I cinque operatori aritmetici previsti dal linguaggio sono:
+ |
somma |
- |
differenza |
* |
moltiplicazione |
/ |
divisione |
% |
modulo (o resto) |
Gli operatori di somma, differenza, moltiplicazione e divisione denotano
le usuali quattro operazioni numeriche. L'operatore di modulo fornisce
il resto della divisione di due numeri interi. Ad esempio, se scriviamo
a = 11 % 3;, viene assegnato alla variabile a il
valore 2 in quanto 2 è proprio il
resto che si ottiene dividendo 11 per 3.
-
Operatori di assegnamento composti ( +=, -=, *=, /=, %=, >>=, <<=,
&=, ^=, |= )
-
Gli operatori di assegnamento composti sono una caratteristica del
C++ che contribuisce alla sua fama di essere un linguaggio
sintetico. Essi permettono di modificare il valore di
una variabile con una sola operazione:
valore += incremento;
è equivalente a valore = valore + incremento;
a -= 5;
è equivalente ad a = a - 5;
a /= b;
è equivalente ad a = a / b;
prezzo *= numero + 1;
è equivalente a prezzo = prezzo * (numero + 1);
e analogamente per le altre operazioni.
-
Incremento e decremento.
-
Un altro esempio di sinteticità si ha con gli operatori
di incremento (++) e di decremento (--). Essi aumentano
o diminuiscono di 1 il valore di una variabile e sono equivalenti
a += 1 e -= 1 rispettivamente.
Quindi:
a++;
a += 1;
a = a+1;
fanno la stessa cosa: aumentano di 1 il valore di a.
Questi operatori si possono usare sia come prefissi che come
postfissi . Ossia possono essere scritti prima della variabile (
++a ) o dopo di essa ( a++ ). Benché in
espressioni semplici come a++ o ++a
gli operatori prefissi e postfissi abbiano lo stesso significato,
in altri casi in cui viene utilizzato il risultato dell'operazione nella
valutazione di un'altra espressione essi assumono un significato diverso:
Se l'operatore di incremento viene usato come prefisso (
++a ) il valore della variabile viene incrementato prima della
valutazione dell'espressione e quindi l'espressione viene valutata usando
il valore incrementato; se l'operatore di incremento viene usato come postfisso
( a++ ) il valore della variabile viene incrementato dopo
la valutazione dell'espressione e quindi l'espressione viene valutata usando
il valore non incrementato. Ecco un esempio della differenza tra i due
modi di usare l'operatore:
Esempio 1 |
Esempio 2 |
B = 3;
A = ++B;
// A è 4, B è 4 |
B = 3;
A = B++;
// A è 3, B è 4 |
Nel primo esempio, la variabile B viene incrementata prima
che il suo valore venga copiato in A mentre nel secondo
esempio viene prima copiato in A il valore
della variabile B e poi viene incrementato
il valore della variabile B.
-
Operatori relazionali ( ==, !=, >, <, >=, <= )
-
Per confrontare i valori di due espressioni si usano gli operatori
relazionali. Come specificato dallo standard ANSI-C++, il risultato
di un operatore relazionale è di tipo bool e
può assumere soltanto uno dei due valori booleani true o
false, a seconda del risultato del confronto.
Ecco la lista degli operatori relazionali del C++:
== |
Uguale |
!= |
Diverso |
> |
Maggiore |
< |
Minore |
>= |
Maggiore o uguale |
<= |
Minore o uguale |
Ed ecco alcuni esempi:
(7 == 5) |
risultato false . |
(5 > 4) |
risultato true . |
(3 != 2) |
risultato true . |
(6 >= 6) |
risultato true . |
(5 < 5) |
risultato false . |
naturalmente, invece di usare soltanto costanti numeriche possiamo usare
qualunque espressioni valida, comprese le variabili. Supponiamo che a=2,
b=3e c=6,
(a == 5) |
risultato false. |
(a*b >= c) |
risultato true in quanto (2*3 >= 6). |
(b+4 > a*c) |
risultato false in quanto (3+4 > 2*6). |
((b=2) == a) |
risultato true. |
Attenzione. L'operatore = (un solo uguale) è differente
dal simbolo == (doppio uguale), il primo è l'operatore
di assegnamento (assegna il valore dell'espressione alla sua destra alla
variabile alla sua sinistra e ritorna tale valore) mentre il secondo è
l'operatore relazionale di uguaglianza che confronta i valori delle due
espressioni che stanno ai suoi lati e ritorna il valore booleano true
o false a seconda che esse abbiano lo stesso valore
o valori diversi. Quindi nell'ultima espressione ((b=2) == a),
viene dapprima assegnato il valore 2 a b e
quindi tale valore viene confrontato con il valore di a,
che è pure 2, e quindi il risultato che si ottiene
è il valore true.
In molti compilatori precedenti la pubblicazione dello standard ANSI-C++,
come pure in C, gli operatori relazionali non ritornano un valore bool
(true o false ) ma ritornano
un valore int con 0 che rappresenta
"false" e un valore diverso da 0 (in
genere 1 ) che rappresenta "true" . |
-
-
Operatori logici ( !, &&, || ).
-
L'operatore ! è l'operatore logico di negazione NOT.
Esso ha un unico operando (di tipo bool) posto alla sua
destra e il suo risultato è l'opposto del valore dell'operando:
se l'operando è true esso ritorna false
, se l'operando è false esso ritorna true
. Ad esempio:
!(5 == 5) |
ritorna false in quanto l'espressione alla sua destra
(5 == 5) è true . |
!(6 <= 4) |
ritorna true in quanto (6 <= 4) è
false
. |
!true |
ritorna false. |
!false |
ritorna true. |
Gli operatori && e || sono
gli operatori logici di congiunzione (AND) e disgiunzione (OR). Essi hanno
due operandi (di tipo bool), uno alla sinistra ed uno alla
destra, e il risultato è quello riportato nella seguente tabella:
Primo
operando
a |
Secondo
operando
b |
Risultato
di
a && b |
Risultato
di
a || b |
true |
true |
true |
true |
true |
false |
false |
true |
false |
true |
false |
true |
false |
false |
false |
false |
Ad esempio:
( (5 == 5) && (3 > 6) ) ritorna
false ( true && false ).
( (5 == 5) || (3 > 6) ) ritorna true
( true || false ) .
-
Operatore condizionale ( ? ).
-
L'operatore condizionale valuta una espressione booleana e ritorna
un valore diverso a seconda che tale valore sia true oppure
false. La sua forma è:
condizione ? risultato1 : risultato2
se condizione è true l'espressione ritorna risultato1,
altrimenti ritorna risultato2.
7==5 ? 4 : 3 |
ritorna 3 perché 7 non è uguale
a 5 . |
7==5+2 ? 4 : 3 |
ritorna 4 perché 7 è uguale a 5+2
. |
5>3 ? a : b |
ritorna a, perché 5 è maggiore
di 3 . |
a>b ? a : b |
ritorna il maggiore dei due, a o b
. |
-
Operatori bit a bit ( &, |, ^, ~, <<, >> ).
-
Gli operatori bit a bit operano in parallelo su tutti i bit degli operandi.
Essi sono operatori di basso livello a cui corrispondono alcune operazioni
assembler. Nella programmazione normale C++ essi non dovrebbero essere
usati.
operatore |
assembler |
Descrizione |
& |
AND |
AND bit a bit |
| |
OR |
OR bit a bit |
^ |
XOR |
OR esclusivo bit a bit |
~ |
NOT |
NOT bit a bit (complemento a uno) |
<< |
SHL |
Spostamento dei bit (shift) a sinistra |
>> |
SHR |
Spostamento dei bit (shift) a destra |
-
Operatori espliciti di conversione di tipo (casting)
-
Gli operatori di conversione servono per convertire valori appartenenti
ad un tipo in valori di un altro tipo. Vi sono diversi modi per fare questo
in C++. Il vecchi modo (stile C) consiste nel far precedere le espressioni
che devono essere convertite dal nome del nuovo tipo racchiuso tra parentesi
():
int i;
float f = 3.14;
i = (int) f;
Il codice precedente converte il numero float 3.14 nel
valore intero 3. L'operatore di conversione è rappresentato
da (int). Un modo più consono allo stile C++
è quello di usare la funzione costruttore: far precedere
l'espressione da convertire, racchiusa tra parentesi, dal nome del nuovo
tipo.
i = int ( f );
Entrambe le forme sono accettate dallo standard ANSI-C++ che inoltre ha
aggiunto altri tipi di conversione adatti alla programmazione ad oggetti.
(vedi Sezione
5.4, Conversioni di tipo avanzate).
-
-
Operatore sizeof()
-
Questo operatore ha un parametro che può essere sia il nome
di un tipo che una espressione. Esso ritorna la memoria, in byte, necessaria
a memorizzare un valore di tale tipo o il valore dell'espressione:
a = sizeof (char);
ritorna 1 in a perché un valore
di tipo char occupa un byte.
Il valore ritornato da è una costante. Esso è quindi
determinato a tempo di compilazione (prima dell'esecuzione del programma).
-
Altri operatori
-
Vedremo nel seguito qualche altro operatore particolare, ad esempio
quelli che operano sui puntatori e quelli specifici per la programmazione
ad oggetti. Essi verranno trattati nelle rispettive sezioni.
Priorità degli operatori
Quando scriviamo espressioni complesse con molti operatori e operandi possono
sorgere dei dubbi sull'ordine in cui gli operatori vengono valutati. Ad
esempio, con l'espressione:
a = 5 + 7 % 2
può sorgere il dubbio tra le seguenti due interpretazioni:
a = 5 + (7 % 2) con risultato 6,
o
a = (5 + 7) % 2 con risultato 0
L'interpretazione corretta è la prima, quella con risultato 6.
Vi è un ordine di priorità prestabilito tra tutti gli operatori
(sia aritmetici che non aritmetici). L'ordine di priorità è
il seguente:
Priorità |
Operatore |
Descrizione |
Associatività |
1 |
:: |
scopo |
Sinistra |
2 |
() [ ] -> . sizeof |
|
Sinistra |
3 |
++ -- |
incremento/decremento |
Destra |
~ |
Complemento a uno (bit a bit) |
! |
NOT |
& * |
Referenziazione e Dereferenziazione (puntatori) |
(tipo) |
Conversione di tipo |
+ - |
Operatori di segno unario |
4 |
* / % |
Operatori aritmetici moltiplicativi |
Sinistra |
5 |
+ - |
Operatori aritmetici additivi |
Sinistra |
6 |
<< >> |
Spostamento dei bit |
Sinistra |
7 |
< <= > >= |
Operatori relazionali |
Sinistra |
8 |
== != |
Operatori relazionali di uguaglianza |
Sinistra |
9 |
& ^ | |
Operatori bit a bit |
Sinistra |
10 |
&& || |
Operatori logici |
Sinistra |
11 |
?: |
Operatore condizionale |
Destra |
12 |
= += -= *= /= %=
>>= <<= &= ^= |= |
Assegnamento |
Destra |
13 |
, |
Operatore virgola, separatore |
Sinistra |
L'associatività specifica in quale ordine vengono valutati
gli operatori con la stessa priorità: partendo da quello più
a destra o da quello più a sinistra.
La precedenza degli operatori in una espressione si può modificare
o rendere evidente usando le parentesi ( e ) come
nell'esempio seguente:
a = 5 + 7 % 2;
si può scrivere come:
a = 5 + (7 % 2);oppure
a = (5 + 7) % 2;
a seconde di come si vuole venga eseguita l'espressione.
Pertanto, quando si vuole scrivere una espressione complicata e non
si è certi della precedenza degli operatori è bene mettere
le parentesi; questo renderà oltretutto più leggibile l'espressione.