Operatori in C e C++
Questa è una lista degli operatori nei linguaggi di programmazione C e C++. Tutti gli operatori seguenti sono implementabili in quest'ultimo linguaggio, mentre invece altri non lo sono in C, come nel caso degli operatori di conversione di tipo (casting), ossia const_cast, static_cast, dynamic_cast, e reinterpret_cast[1][2][3].
Molti degli operatori disponibili in C e C++ sono implementabili pure in altri linguaggi della cosiddetta “famiglia C”, quali C#, D, ma anche Java, Perl e PHP, mantenendo le medesime caratteristiche mostrate (arietà, posizione e associatività)[4][5].
Sintassi degli operatori
Nelle tabelle seguenti, a, b e c rappresentano valori validi qualsiasi (literals, valori da variabili, oppure return value) o, in alcuni casi specifici, nomi di oggetti o lvalues. R, S e T indicano qualsiasi tipo, mentre K indica un tipo di classe o un tipo enum[6][7].
Operatori aritmetici
Tutti gli operatori aritmetici esistono sia in C e C++ e possono essere, come già indicato, sovraccaricati solo in C++[8].
| Nome operatore | Sintassi | Esempi di implementazione in C++ | ||
|---|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | |||
| Addizione | a+b
|
R K::operator +(S b);
|
R operator +(K a, S b);
| |
| Sottrazione | a-b
|
R K::operator -(S b);
|
R operator -(K a, S b);
| |
| Unario più | +a
|
R K::operator +(); | R operator +(K a); | |
| Unario meno | -a | R K::operator -(); | R operator -(K a); | |
| Moltiplicazione | a * b
|
R K::operator *(S b);
|
R operator *(K a, S b);
| |
| Divisione | a / b
|
R K::operator /(S b);
|
R operator /(K a, S b);
| |
| Modulo | a % b
|
R K::operator %(S b);
|
R operator %(K a, S b);
| |
| Incremento | Prefisso | ++a
|
R& K::operator ++();
|
R& operator ++(K& a);
|
| Postfisso | a++
|
R K::operator ++(int);
|
R operator ++(K& a, int);
| |
| Il C++ utilizza il parametro fittizio senza nome int per differenziare gli operatori di incremento prefisso e postfisso. | ||||
| Decremento | Prefisso | --a
|
R& K::operator --();
|
R& operator --(K& a);
|
| Postfisso | a--
|
R K::operator --(int);
|
R operator --(K& a, int);
| |
| Il C++ utilizza il parametro fittizio senza nome int per differenziare gli operatori di incremento prefisso e postfisso. | ||||
Operatori relazionali
Tutti gli operatori di confronto possono essere sovraccaricati solo in C++. Dal C++20, l'operatore di disuguaglianza viene generato automaticamente se viene definito operator== e tutti e quattro gli operatori relazionali vengono generati automaticamente se viene definito operator<=>.
| Nome operatore | Sintassi | Incluso in C | Esempi di implementazione in C++ | |
|---|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | |||
| Uguale | a = b
|
Template:Sit | bool K::operator ==(S const& b) const;
|
bool operator ==(K const& a, S const& b);
|
| Diverso | a != b |
Template:Sit | bool K::operator !=(S const& b) const;
|
bool operator !=(K const& a, S const& b);
|
| Maggiore di | a > b |
Template:Sit | bool K::operator >(S const& b) const;
|
bool operator >(K const& a, S const& b);
|
| Minore di | a < b |
Template:Sit | bool K::operator <(S const& b) const;
|
bool operator <(K const& a, S const& b);
|
| Maggiore o uguale a | a >= b |
Template:Sit | bool K::operator >=(S const& b) const;
|
bool operator >=(K const& a, S const& b);
|
| Minore o uguale a | a <= b |
Template:Sit | bool K::operator <=(S const& b) const;
|
bool operator <=(K const& a, S const& b);
|
Operatori logici (o booleani)
Tutti gli operatori logici (o booleani[9]) sono esistenti sia in C che in C++ e possono essere chiaramente sovraccaricati solo in quest'ultimo linguaggio di programmazione.
Nonostante la possibilità di sovraccarico in C++, tale operazione è sconsigliata con AND logico e OR logico sia sconsigliato perché, come operatori sovraccaricati, si comporterebbero come normali chiamate di funzione, il che significa che entrambi i loro operandi verrebbero valutati, perdendo di conseguenza la loro importante valutazione di McCarthy. [10]
| Nome dell'operatore | Sintassi | Esempi di implementazione in C++ | |
|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | ||
| NOT logico | ! a
|
bool K::operator !();
|
bool operator !(K a);
|
| AND logico | a && b
|
bool K::operator &&(S b);
|
bool operator &&(K a, S b);
|
| OR logico | a || b
|
bool K::operator ||(S b);
|
bool operator ||(K a, S b);
|
Operatori bit a bit
Tutti gli operatori bit a bit (o di manipolazione dei bit) esistono sia C che C++ e possono essere sovraccaricati soltanto nel linguaggio inventato da Bjarne Stroustrup[11].
| Nome dell'operatore | Sintassi | Esempi di implementazione in C++ | |
|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | ||
| Complemento a uno (inversione di tutti i bit) | ~a
|
R K::operator ~();
|
R operator ~(K a);
|
| AND bit a bit | a & b
|
R K::operator &(S b);
|
R operator &(K a, S b);
|
| OR inclusivo bit a bit | a | b
|
R K::operator |(S b);
|
R operator |(K a, S b);
|
| OR esclusivo bit a bit (OR exclusive, XOR) | a ^ b
|
R K::operator ^(S b);
|
R operator ^(K a, S b);
|
| Spostamento di tutti i bit verso sinistra | a << b
|
R K::operator <<(S b);
|
R operator <<(K a, S b);
|
| Spostamento di tutti i bit verso destra | a >> b
|
R K::operator >>(S b);
|
R operator >>(K a, S b);
|
Operatori ed espressioni di assegnamento
Tutti gli operatori e le espressioni di assegnamento sono esistenti sia in C che in C++ e possono essere chiaramente sovraccaricate solo in quest'ultimo linguaggio di programmazione.
Per gli operatori indicati, la semantica dell'espressione di assegnazione combinata incorporata a ⊚= b è equivalente a a = a ⊚ b, eccetto per il fatto che a viene valutata una sola volta.
| Tipologia assegnamento | Sintassi | Esempi di implementazione in C++ | |
|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | ||
| Espressione semplice di assegnamento | Template:Tutto attaccato | R& K::operator =(S b);
|
Template:ND |
| Assegnamenti composti | a += b
|
R& K::operator +=(S b);
|
R& operator +=(K& a, S b);
|
a -= b
|
R& K::operator -=(S b);
|
R& operator -=(K& a, S b);
| |
a *= b
|
R& K::operator *=(S b);
|
R& operator *=(K& a, S b);
| |
a /= b
|
R& K::operator /=(S b);
|
R& operator /=(K& a, S b);
| |
a %= b
|
R& K::operator %=(S b);
|
R& operator %=(K& a, S b);
| |
a &= b
|
R& K::operator &=(S b);
|
R& operator &=(K& a, S b);
| |
a |= b
|
R& K::operator |=(S b);
|
R& operator |=(K& a, S b);
| |
a ^= b
|
R& K::operator ^=(S b);
|
R& operator ^=(K& a, S b);
| |
a <<= b
|
R& K::operator <<=(S b);
|
R& operator <<=(K& a, S b);
| |
a >>= b
|
R& K::operator >>=(S b);
|
R& operator >>=(K& a, S b);
| |
Operatori membro e puntatore
| Nome operatore[12] | Sintassi | Ammette overload (sovraccarico) in C++ | Implementabile in C | Esempi di implementazione in C++ | |
|---|---|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | ||||
| Indicizzazione | a[b]
|
Template:Sit | Template:Sit | R& K::operator [](S b);
|
Template:ND |
| Deferenziazione | *a
|
Template:Sit | Template:Sit | R& K::operator *(); | R& operator *(K a); |
| Indirizzo | &a
|
Template:Sit | Template:Sit | R* K::operator &(); | R* operator &(K a); |
| Deferenziazione e selezione | a->b
|
Template:Sit | Template:Sit | R* K::operator ->(); | Template:ND |
| Selezione (object.member) | a.b
|
Template:Not | Template:Sit | Template:ND | Template:ND |
| Deferenziazione e selezione con puntatore a membro | a->*b
|
Template:Sit | Template:Not | R& K::operator ->*(S b); | R& operator ->*(K a, S b); |
| Selezione con puntatore a membro | a.*b
|
Template:Not | Template:Not | Template:ND | Template:ND |
Altri operatori
| Nome operatore | Sintassi | Ammette overload (sovraccarico) in C++ | Implementabile in C | Esempi di implementazione in C++ | |
|---|---|---|---|---|---|
| Come membro della classe K | Fuori dalla classe | ||||
| Chiamata di funzione | a(a1, a2)
|
Template:Sit | Template:Sit | R K::operator ()(S a, T b, ...); | |
| Virgola | a, b
|
Template:Sit | Template:Sit | R K::operator ,(S b);
|
R operator ,(K a, S b);
|
| Espressione condizionale | a ? b : c
|
Template:Not | Template:Sit | Template:ND | Template:ND |
| Risolutore di visibilità | a::b
|
Template:Not | Template:Not | Template:ND | Template:ND |
| Dimensione di oggetto o di tipo (sizeof) | sizeof a
|
Template:Not | Template:Sit | Template:ND | Template:ND |
| Conversione di tipo static_cast | static_cast<R>(a)
|
Template:Sit | Template:Not | K::operator R();
|
Template:ND |
| Conversione const const_cast | const_cast<R>(a)
|
Template:Not | Template:Not | Template:ND | Template:ND |
| Allocazione | new R
|
Template:Sit | Template:Not | void* K::operator new(size_t x);
|
void* operator new(size_t x);
|
| Allocazione di array | new R[n]
|
Template:Sit | Template:Not | void* K::operator new[](size_t a);
|
void* operator new[](size_t a);
|
| Deallocazione | delete a
|
Template:Sit | Template:Not | void K::operator delete(void* a);
|
void operator delete(void* a);
|
| Deallocazione di array | delete[] a
|
Template:Sit | Template:Not | void K::operator delete[](void* a);
|
void operator delete[](void* a);
|
Overloading degli operatori
C++ possiede molti operatori già predefiniti in grado di operare su vari tipi di dato, perciò si può parlare di “operatori già sovraccaricati”. Per esempio l’operatore + può essere implementato per sommare sia due variabili di tipo int (interi), sia due variabili di tipo float o double (variabili a virgola mobile).
Oltre a quando detto in precedenza, il programmatore può anche “estendere” l’operatività di ciascuno di essi; per esempio operandi complessi definiti con le classi, si potrebbero trattare anche come se fossero dati semplici[1].
In C++ è possibile sovraccaricare tutti gli operatori predefiniti, con l’eccezione su accesso al membro (.), indirezione di accesso al membro (.*) e risoluzione di ambito (::).
Nel caso degli operatori, il numero degli operandi e la priorità dell’operatore sovraccaricato sono le stesse dell’operatore predefinito, mentre il nuovo operatore può essere definito come una funzione membro oppure come una funzione friend (funzione amica)[14].
Proprietà degli operatori
Ogni operatore possiede delle proprietà, in modo tale da permettere l'interpretazione univoca del significato di ogni singola espressione. Gli esempi che seguono sono tutti applicabili al linguaggio C++ e, a seconda dei casi, anche al C[15].
Posizione
Un operatore può precedere gli operandi (o argomenti), seguirli oppure né precederli né seguirli[12]. In questi casi parleremo rispettivamente di operatori prefissi, postfissi oppure infissi.
Numero di operandi
Ogni operatore può avere un numero diverso di operandi (arietà).
a[b]
Nel caso riportato, l'operatore di indicizzazione possiede due operandi, ossia le parentesi quadre. L'arietà può essere anche di tre operandi, come nel caso degli operatori condizionali, riportato di seguito:
e1 ? e2 : e3
Precedenza degli operatori
Ogni operatore possiede una propria precedenza[16][17], rappresentata attraverso un numero naturale tra 1 e 18 in ordine decrescente, dove più è piccolo il numero, maggiore sarà la priorità; per esempio un operatore con priorità 1 avrà maggiore priorità su un operatore con priorità 13.
Nell'esempio che segue è possibile osservare una semplice applicazione pratica delle precedenze:
#include <iostream>
using namespace std;
int main () {
int a = 5;
int b = 6;
int c = 8;
int op = a+b*c;
cout << op << endl; // Stampa a schermo
return 0;
}
L'operatore moltiplicazione (*) possiede priorità 5, mentre l'operatore addizione (+) possiede priorità 6; pertanto il risultato a schermo sarà 53 e non 19.
Associatività degli operatori
L'associatività indica l'ordine in cui vengono eseguiti gli operatori aventi la stessa priorità tra loro[12]. Viene riportato un semplice esempio con gli operatori di divisione (priorità 5).
#include <iostream>
using namespace std;
int main (){
float a = 5.0;
float b = 6.0;
float c = 8.0;
float div = a/b/c;
cout << div << endl; // Stampa a schermo
return 0;
}
Nell'esempio precedente la stampa a schermo sarà 0.104167 perché l'operatore di divisione segue associatività a sinistra e, quindi, il calcolatore avrà eseguito la seguente equazione:
.
Tabella delle precedenze e delle associatività
Nella tabella seguente sono elencati gli operatori di C e C++ in ordine di priorità con le loro rispettive associatività. Essi sono sempre implementabili su C++, mentre, quelli appositamente indicati nella penultima colonna da sinistra, non lo sono in C[12][17].
| Priorità | Operatore | Nome | Implementabile in C | Associatività |
|---|---|---|---|---|
| 1
(priorità massima) |
class-name :: member
|
Risolutore di visibilità | Template:Not | sinistra |
:: member
|
Risolutore globale di visibilità | Template:Not | destra | |
| 2 | object . member
|
Selezione | Template:Sit | sinistra |
pointer -> member
|
Deferenziazione e selezione | Template:Sit | sinistra | |
array[ rvalue ]
|
Indicizzazione | Template:Sit | sinistra | |
function ( actual-argument-list )
|
Chiamata di funzione | Template:Sit | sinistra | |
lvalue ++
|
Postincremento | Template:Sit | destra | |
lvalue --
|
Postdecremento | Template:Sit | destra | |
static_cast type<rvalue>
|
Conversione di tipo | Template:Not | sinistra | |
const_cast type<rvalue>
|
Conversione const | Template:Not | sinistra | |
| 3 | sizeof object
|
Dimensione
di oggetto di tipo |
Template:Sit | destra |
++ lvalue
|
Preincremento | Template:Sit | destra | |
-- lvalue
|
Predecremento | Template:Sit | destra | |
~ rvalue
|
Complemento bit a bit | Template:Sit | destra | |
! rvalue
|
Negazione | Template:Sit | destra | |
- rvalue
|
Meno unitario | Template:Sit | destra | |
+ rvalue
|
Più unitario | Template:Sit | destra | |
& rvalue
|
Indirizzo | Template:Sit | destra | |
* rvalue
|
Deferenziazione | Template:Sit | destra | |
new type
|
Allocazione | Template:Not | destra | |
new type[]
|
Allocazione di array | Template:Not | destra | |
delete pointer
|
Deallocazione | Template:Not | destra | |
delete[] pointer
|
Deallocazione di array | Template:Not | destra | |
| 4 | object .* pointer-to-member
|
Selezione con puntatore a membro | Template:Not | sinistra |
pointer ->* pointer-to-member
|
Deferenziazione e selezione con puntatore a membro | Template:Not | sinistra | |
| 5 | rvalue * rvalue
|
Moltiplicazione | Template:Sit | sinistra |
rvalue / rvalue
|
Divisione | Template:Sit | sinistra | |
rvalue % rvalue
|
Modulo | Template:Sit | sinistra | |
| 6 | rvalue + rvalue
|
Addizione | Template:Sit | sinistra |
rvalue - rvalue
|
Sottrazione | Template:Sit | sinistra | |
| 7 | rvalue << rvalue
|
Traslazione sinistra | Template:Sit | sinistra |
rvalue >> rvalue
|
Traslazione destra | Template:Sit | sinistra | |
| 8 | rvalue < rvalue
|
Minore | Template:Sit | sinistra |
rvalue <= rvalue
|
Minore o uguale | Template:Sit | sinistra | |
rvalue > rvalue
|
Maggiore | Template:Sit | sinistra | |
rvalue >= rvalue
|
Maggiore o uguale | Template:Sit | sinistra | |
| 9 | rvalue == rvalue
|
Uguale | Template:Sit | sinistra |
rvalue != rvalue
|
Diverso | Template:Sit | sinistra | |
| 10 | rvalue & rvalue
|
AND bit a bit | Template:Sit | sinistra |
| 11 | rvalue ^ rvalue
|
OR esclusivo bit a bit | Template:Sit | sinistra |
| 12 | rvalue | rvalue
|
OR bit a bit | Template:Sit | sinistra |
| 13 | rvalue && rvalue
|
AND logico | Template:Sit | sinistra |
| 14 | rvalue || rvalue
|
OR logico | Template:Sit | sinistra |
| 15 | co_await
|
Coroutine | Template:Not | destra |
| 16 | rvalue ? rvalue : rvalue
|
Espressione condizionale | Template:Sit | sinistra |
| 17 | lvalue = rvalue
|
Assegnamento | Template:Sit | destra |
lvalue += rvalue
|
Addizione e assegnamento | Template:Sit | destra | |
lvalue -= rvalue
|
Sottrazione e assegnamento | Template:Sit | destra | |
lvalue *= rvalue
|
Moltiplicazione e assegnamento | Template:Sit | destra | |
lvalue /= rvalue
|
Divisione e assegnamento | Template:Sit | destra | |
lvalue %= rvalue
|
Modulo e assegnamento | Template:Sit | destra | |
lvalue &= rvalue
|
AND bit a bit e assegnamento | Template:Sit | destra | |
lvalue |= rvalue
|
OR bit a bit e assegnamento | Template:Sit | destra | |
lvalue ^= rvalue
|
OR esclusivo bit a bit e assegnamento | Template:Sit | destra | |
lvalue <<= rvalue
|
Traslazione a sinistra e assegnamento | Template:Sit | destra | |
lvalue =>> rvalue
|
Traslazione a destra e assegnamento | Template:Not | destra | |
| 18
(priorità minima) |
expression , expression
|
Virgola | Template:Sit | sinistra |
Critiche sulle precedenze degli operatori
La precedenza degli operatori logici bitwise è stata al centro di numerose critiche[18][19], poiché concettualmente, & e | sono operatori aritmetici come * e +.
Per esempio, l'espressione a & b == 7 viene sintatticamente analizzata come a & (b == 7), mentre l'espressione a + b == 7 viene analizzata come (a + b) == 7. Ciò richiede l'uso delle parentesi più spesso di quanto sarebbe altrimenti necessario.
Storicamente, non esisteva una distinzione sintattica tra gli operatori bit a bit e quelli logici. Nei linguaggi BCPL, B e nelle prime versioni di C, gli operatori && e || non esistevano proprio; invece, & | aveva un significato diverso a seconda che venisse usato in un “contesto di valore di verità” (cioè quando ci si aspettava il ritorno di un valore booleano, come in if (a==b & c) {...} e si comportava come un operatore logico, ma in c = a & b si comportava invece come un operatore bit a bit).
La sintassi attuale è stata mantenuta soltanto per consentire la retrocompatibilità con le installazioni già esistenti.
Peraltro, in C++ (e nelle versioni successive di C) le operazioni di uguaglianza, con l'eccezione dell'operatore di confronto logico a tre, producono valori di tipo bool che sono concettualmente un singolo bit (1 o 0) e come tali non appartengono propriamente alle operazioni bit a bit.
Sinonimi in C++
C++ definisce una serie di keywords che possono essere implementate come sinonimi rispetto agli operatori[20]; tali definizioni non sono assolutamente implementabili nel linguaggio C.
| Keyword | Operator |
|---|---|
and
|
&&
|
and_eq
|
&=
|
bitand
|
&
|
bitor
|
|
|
compl
|
~
|
not
|
!
|
not_eq
|
!=
|
or
|
||
|
or_eq
|
|=
|
xor
|
^
|
xor_eq
|
^=
|
Questi possono essere utilizzati esattamente come sostituti dei rispettivi simboli di punteggiatura; ciò significa, per esempio, che le espressioni (a > 0 AND NOT flag) e (a > 0 && flag) avranno un significato assolutamente identico.
Note
- ↑ 1,0 1,1 Template:Cita libro
- ↑ Template:Cita libro
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ L'accezione booleana è stata coniata in onore del matematico George Boole.
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ 12,0 12,1 12,2 12,3 Template:Cita libro
- ↑ Per le conversioni definite dall'utente, il tipo di ritorno corrisponde implicitamente e necessariamente al nome dell'operatore, a meno che il tipo non sia dedotto. (es.
operator auto(), operator decltype(auto)()etc.). - ↑ Template:Cita pubblicazione
- ↑ Template:Cita pubblicazione
- ↑ The ISO C 1999 standard, section 6.5.6 note 71 (Technical report). ISO. 1999.
- ↑ 17,0 17,1 Template:Cita pubblicazione
- ↑ Template:Cita web
- ↑ Template:Cita web
- ↑ ISO/IEC 14882:1998(E) Programming Language C++. open-std.org – The C++ Standards Committee. 1 September 1998. pp. 40–41.
Bibliografia
Voci correlate
Collegamenti esterni
- Volle, Adam. "C++". Encyclopedia Britannica, 19 Jun. 2024, https://www.britannica.com/technology/C-computer-language;
- Microsoft C++, C, and Assembler documentation.
Template:C++Template:Linguaggio C Template:Principali linguaggi di programmazioneTemplate:Controllo di autorità