[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home] [volume] [parte]


Capitolo 744.   Operatori ed espressioni del linguaggio C

L'operatore è qualcosa che esegue un qualche tipo di funzione, su uno o più operandi, restituendo un valore.(1) Il valore restituito è di tipo diverso a seconda degli operandi utilizzati. Per esempio, la somma di due interi genera un risultato intero. Gli operandi descritti di seguito sono quelli più comuni e importanti.

Le espressioni sono formate spesso dalla valutazione di sottoespressioni (espressioni più piccole). Va osservato che ci sono circostanze in cui il contesto non impone che ci sia un solo ordine possibile nella valutazione delle sottoespressioni, ma il programmatore deve tenere conto di questa possibilità, per evitare che il risultato dipenda dalle scelte non prevedibili del compilatore.

Tabella 744.1. Ordine di precedenza tra gli operatori previsti nel linguaggio C. Gli operatori sono raggruppati a livelli di priorità equivalente, partendo dall'alto con la priorità maggiore, scendendo progressivamente alla priorità minore. Le variabili a, b e c rappresentano la collocazione delle sottoespressioni da considerare ed esprimono l'ordine di associatività: prima a, poi b, poi c.

Operatori Annotazioni
(a)
[a]
a->b  a.b
Le parentesi tonde usate per raggruppare una porzione di espressione hanno la precedenza su ogni altro operatore. Le parentesi quadre riguardano gli array; gli operatori -> e ., riguardano le strutture e le unioni.
!a  ~a  ++a  --a  +a  -a
*a  &a
(tipo)  sizeof a
Gli operatori + e - di questo livello sono da intendersi come «unari», ovvero si riferiscono al segno di quanto appare alla loro destra. Gli operatori * e & di questo livello riguardano la gestione dei puntatori; le parentesi tonde si riferiscono al cast.
a*b  a/b  a%b
Moltiplicazione, divisione e resto della divisione intera.
a+b  a-b
Somma e sottrazione.
a<<b  a>>b
Scorrimento binario.
a<b  a<=b  a>b  a=>b
Confronto.
a==b  a!=b
Confronto.
a&b
AND bit per bit.
a^b
XOR bit per bit.
a|b
OR bit per bit.
a&&b
AND nelle espressioni logiche.
a||b
OR nelle espressioni logiche.
c?b:a
Operatore condizionale
b=a  b+=a  b-=a
b*=a  b/=a  b%=a
b&=a  b^=a  b|=a
b<<=a  b>>=a
Operatori di assegnamento.
ab
Sequenza di espressioni (espressione multipla).

744.1   Tipo del risultato di un'espressione

Un'espressione è un qualche cosa composto da operandi e da operatori, che nel complesso si traduce in un qualche risultato. Per esempio, 5+6 è un'espressione aritmetica che si traduce nel numero 11. Così come le variabili, le costanti simboliche e le costanti letterali, hanno un tipo, con il quale si definisce in che modo vengono rappresentate in memoria, anche il risultato delle espressioni ha un tipo, in quanto tale risultato deve poi essere rappresentabile in memoria in qualche modo.

La regola che definisce di che tipo è il risultato di un'espressione è piuttosto articolata, ma in generale è sufficiente rendersi conto che si tratta della scelta più logica in base al contesto. Per esempio, l'espressione già vista, 5+6, essendo la somma di due interi con segno, dovrebbe dare come risultato un intero con segno. Nello stesso modo, un'espressione del tipo 5.1-6.3, essendo costituita da operandi in virgola mobile (precisamente double), dà il risultato -1,2, rappresentato sempre in virgola mobile (sempre double). Va osservato che la regola di principio vale anche per le divisioni, per cui 11/2 dà 5, di tipo intero (int), perché per avere un risultato in virgola mobile occorrerebbe invece scrivere 11.0/2.0.

Si osservi che se in un'espressione si mescolano operandi interi assieme a operandi in virgola mobile, il risultato dell'espressione dovrebbe essere di tipo a virgola mobile. Per esempio, 5+6.3 dà il valore 11,3, in virgola mobile (double). Inoltre, se gli operandi hanno tra loro un rango differente, dovrebbe prevalere il rango maggiore.

744.1.1   Esercizio

Indicare il tipo che si dovrebbe ottenere dalla valutazione delle espressioni proposte. Il primo caso appare risolto, come esempio:

Espressione Tipo che dovrebbe avere il risultato dell'espressione
4+3.5
double
4+4
 
 
 
4/3
 
 
 
4.0/3
 
 
 
4L*3
 
 
 

744.2   Operatori aritmetici

Gli operatori che intervengono su valori numerici sono elencati nella tabella successiva. Per dare un significato alle descrizioni della tabella, occorre tenere presenta una caratteristica importante del linguaggio, per la quale, la maggior parte delle espressioni restituisce un valore. Per esempio, b = a = 1 fa sì che la variabile a ottenga il valore 1 e che, successivamente, la variabile b ottenga il valore di a. In questo senso, al problema dell'ordine di precedenza dei vari operatori si aggiunge anche l'ordine in cui le espressioni restituiscono un valore. Per esempio, d = e++ comporta l'incremento di una unità del contenuto della variabile e, ma ciò solo dopo averne restituito il valore che viene assegnato alla variabile d. Pertanto, se inizialmente la variabile e contiene il valore 1, dopo l'elaborazione dell'espressione completa, la variabile d contiene il valore 1, mentre la variabile e contiene il valore 2.

Tabella 744.3. Elenco degli operatori aritmetici e di quelli di assegnamento relativi a valori numerici.

Operatore e
operandi
Descrizione
++op
Incrementa di un'unità l'operando prima che venga restituito il suo valore.
op++
Incrementa di un'unità l'operando dopo averne restituito il suo valore.
--op
Decrementa di un'unità l'operando prima che venga restituito il suo valore.
op--
Decrementa di un'unità l'operando dopo averne restituito il suo valore.
+op
Non ha alcun effetto.
-op
Inverte il segno dell'operando (prima di restituirne il valore).
op1 + op2
Somma i due operandi.
op1 - op2
Sottrae dal primo il secondo operando.
op1 * op2
Moltiplica i due operandi.
op1 / op2
Divide il primo operando per il secondo.
op1 % op2
Calcola il resto della divisione tra il primo e il secondo operando, i quali devono essere costituiti da valori interi.
var = valore
Assegna alla variabile il valore alla destra.
op1 += op2
op1 = (op1 + op2)
op1 -= op2
op1 = (op1 - op2)
op1 *= op2
op1 = (op1 * op2)
op1 /= op2
op1 = (op1 / op2)
op1 %= op2
op1 = (op1 % op2)

744.2.1   Esercizio

Osservando i pezzi di codice indicati, si scriva il valore contenuto nelle variabili a cui si assegna un valore, attraverso l'elaborazione di un'espressione. Il primo caso appare risolto, come esempio:

Codice Valore contenuto nelle variabili dopo l'esecuzione del codice mostrato
int a = 3;
int b;
b = a++;
 
a contiene 4;
b contiene 3.
 
int a = 3;
int b;
b = --a;
 
 
 
 
int a = 3;
int b = 2;
b = a + b;
 
 
 
 
int a = 7;
int b = 2;
b = a % b;
 
 
 
 
int a = 7;
int b;
b = (a = a * 2);
 
 
 
 
int a = 3;
int b = 2;
b += a;
 
 
 
 
int a = 7;
int b = 2;
b %= a;
 
 
 
 
int a = 7;
int b;
b = (a *= 2);
 
 
 
 

744.2.2   Esercizio

Scrivere diversi programmi per verificare l'esercizio precedente. Viene proposto il primo, da usare come modello per gli altri:

#include <stdio.h>
int main (void)
{
    int a = 3;
    int b;
    b = a++;
    printf ("a contiene %d;\n", a);
    printf ("b contiene %d.\n", b);
    getchar ();
    return 0;
}

744.3   Operatori di confronto

Gli operatori di confronto determinano la relazione tra due operandi. Il risultato dell'espressione composta da due operandi posti a confronto è un numero intero (int) e precisamente si ottiene uno se il confronto è valido e zero in caso contrario. Gli operatori di confronto sono elencati nella tabella successiva.

Il linguaggio C non ha una rappresentazione specifica per i valori booleani Vero e Falso,(2) ma si limita a interpretare un valore pari a zero come Falso e un valore diverso da zero come Vero. Va osservato, quindi, che il numero usato come valore booleano, può essere espresso anche in virgola mobile, benché sia preferibile di gran lunga un intero normale.

Tabella 744.6. Elenco degli operatori di confronto. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

Operatore e
operandi
Descrizione
op1 == op2
1 (Vero) se gli operandi si equivalgono.
op1 != op2
1 (Vero) se gli operandi sono differenti.
op1 < op2
1 (Vero) se il primo operando è minore del secondo.
op1 > op2
1 (Vero) se il primo operando è maggiore del secondo.
op1 <= op2
1 (Vero) se il primo operando è minore o uguale al secondo.
op1 >= op2
1 (Vero) se il primo operando è maggiore o uguale al secondo.

744.3.1   Esercizio

Osservando i pezzi di codice indicati, si scriva il valore contenuto nella variabile c. Il primo caso appare risolto, come esempio:

Codice Valore contenuto nella variabile c l'esecuzione del codice mostrato
int a = 5;
signed char b = -4;
int c = a > b;
 
c contiene 1.
 
int a = 4 + 1;
signed char b = 5;
int c = a == b;
 
 
 
int a = 4 + 1;
signed char b = 5;
int c = a != b;
 
 
 
unsigned int a = 4 + 3;
signed char b = -5;
int c = a >= b;
 
 
 
unsigned int a = 4 + 3;
signed char b = -5;
int c = a <= b;
 
 
 

744.3.2   Esercizio

Scrivere diversi programmi per verificare l'esercizio precedente. Viene proposto il primo, da usare come modello per gli altri:

#include <stdio.h>
int main (void)
{
    int a = 5;
    signed char b = -4;
    int c = a > b;
    printf ("(%d > %d) produce %d\n", a, b, c);
    getchar ();
    return 0;
}

744.4   Operatori logici

Quando si vogliono combinare assieme diverse espressioni logiche, comprendendo in queste anche delle variabili che contengono un valore booleano, si utilizzano gli operatori logici (noti normalmente come: AND, OR, NOT, ecc.). Il risultato di un'espressione logica complessa è quello dell'ultima espressione elementare valutata effettivamente, in quanto le sottoespressioni che non possono cambiare l'esito della condizione complessiva non vengono valutate. Gli operatori logici sono elencati nella tabella successiva.

Tabella 744.9. Elenco degli operatori logici. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

Operatore e
operandi
Descrizione
! op
Inverte il risultato logico dell'operando.
op1 && op2
Se il risultato del primo operando è Falso non valuta il secondo.
op1 || op2
Se il risultato del primo operando è Vero non valuta il secondo.

Un tipo particolare di operatore logico è l'operatore condizionale, il quale permette di eseguire espressioni diverse in relazione al risultato di una condizione. La sua sintassi si esprime nel modo seguente:

condizione ? espressione1 : espressione2

In pratica, se l'espressione che rappresenta la condizione si avvera, viene eseguita la prima espressione che segue il punto interrogativo, altrimenti viene eseguita quella che segue i due punti.

744.4.1   Esercizio

Osservando i pezzi di codice indicati, si scriva il valore contenuto nella variabile c. Il primo caso appare risolto, come esempio:

Codice Valore contenuto nella variabile c dopo l'esecuzione del codice mostrato
int a = 5;
signed char b = -4;
int c = ! (a > b);
 
c contiene 0.
 
int a = 4;
signed char b = (3 < 5);
int c = a && b;
 
 
 
int a = 4;
signed char b = (3 < 5);
int c = a || b;
 
 
 
unsigned int a = 4 + 3;
signed char b = -5;
int c = (b > 0) || (a > b);
 
 
 

744.5   Operatori binari

Il linguaggio C consente di eseguire alcune operazioni binarie, sui valori interi, come spesso è possibile fare con un linguaggio assemblatore, anche se non è possibile interrogare degli indicatori (flag) che informino sull'esito delle azioni eseguite. Sono disponibili le operazioni elencate nella tabella successiva.

Tabella 744.11. Elenco degli operatori binari. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

Operatore e
operandi
Descrizione
op1 & op2
AND bit per bit.
op1 | op2
OR bit per bit.
op1 ^ op2
XOR bit per bit (OR esclusivo).
op1 << op2
Scorrimento a sinistra di op2 bit. A destra vengono aggiunti bit a zero
op1 >> op2
Scorrimento a destra di op2 bit. Il valore dei bit aggiunti a sinistra potrebbe tenere conto del segno.
~op1
Complemento a uno.
op1 &= op2
op1 = (op1 & op2)
op1 |= op2
op1 = (op1 | op2)
op1 ^= op2
op1 = (op1 ^ op2)
op1 <<= op2
op1 = (op1 << op2)
op1 >>= op2
op1 = (op1 >> op2)
op1 ~= op2
op1 = ~op2

A seconda del compilatore e della piattaforma, lo scorrimento a destra potrebbe essere di tipo aritmetico, ovvero potrebbe tenere conto del segno. Pertanto, non potendo fare sempre affidamento su questa ipotesi, è prudente far sì che i valori di cui si fa lo scorrimento a destra siano sempre senza segno, o comunque positivi.

Per aiutare a comprendere il meccanismo vengono mostrati alcuni esempi. In particolare si utilizzano due operandi di tipo char (a 8 bit) senza segno: a contenente il valore 42, pari a 001010102; b contenente il valore 51, pari a 001100112.

and or xor

Lo scorrimento, invece, viene mostrato sempre solo per una singola unità: a contenente sempre il valore 42; b contenente il valore 1.

scorrimento e complemento

744.5.1   Esercizio

Osservando i pezzi di codice indicati, si scriva il valore contenuto nella variabile c. L'architettura a cui ci si riferisce prevede l'uso del complemento a due per la rappresentazione dei numeri negativi e lo scorrimento a destra è di tipo aritmetico (in quanto preserva il segno). I primi casi appaiono risolti, come esempio:

Codice Valore contenuto nella variabile c dopo l'esecuzione del codice mostrato
int a = -20;
int c = a >> 1;
 
c contiene -10.
 
int a = 5;
int b = 12;
int c = a & b;
 
 
 
int a = 5;
int b = 12;
int c = a | b;
 
 
 
int a = 5;
int b = 12;
int c = a ^ b;
 
 
 
int a = 5;
int c = a << 1;
 
 
 
int a = 21;
int c = a >> 1;
 
 
 

744.5.2   Esercizio

Scrivere diversi programmi per verificare l'esercizio precedente. Viene proposto un esempio, riferito a un caso che non appare nell'esercizio precedente, con cui si ottiene il complemento a uno:

#include <stdio.h>
int main (void)
{
    int a = 21;
    int c = ~a;
    printf ("c contiene %d\n", c);
    getchar ();
    return 0;
}

744.6   Conversione di tipo

Quando si assegna un valore a una variabile, nella maggior parte dei casi, il contesto stabilisce il tipo di questo valore in modo corretto. Di fatto, è il tipo della variabile ricevente che stabilisce la conversione necessaria. Tuttavia, il problema si pone anche durante la valutazione di un'espressione.

Per esempio, 5/4 viene considerata la divisione di due interi e, di conseguenza, l'espressione restituisce un valore intero, cioè 1. Diverso sarebbe se si scrivesse 5.0/4.0, perché in questo caso si tratterebbe della divisione tra due numeri a virgola mobile (per la precisione, di tipo double) e il risultato è un numero a virgola mobile.

Quando si pone il problema di risolvere l'ambiguità si utilizza esplicitamente la conversione del tipo, attraverso un cast:

(tipo) espressione

In pratica, si deve indicare tra parentesi tonde il nome del tipo di dati in cui deve essere convertita l'espressione che segue. Il problema sta nella precedenza che ha il cast nell'insieme degli altri operatori e in generale conviene utilizzare altre parentesi per chiarire la relazione che ci deve essere.

int x = 10;
double y;
...
y = (double) x/9;

In questo caso, la variabile intera x viene convertita nel tipo double (a virgola mobile) prima di eseguire la divisione. Dal momento che il cast ha precedenza sull'operazione di divisione, non si pongono problemi, inoltre, la divisione avviene trasformando implicitamente il 9 intero in un 9,0 di tipo double. In pratica, l'operazione avviene utilizzando valori double e restituendo un risultato double.

744.6.1   Esercizio

Indicare il tipo che si dovrebbe ottenere dalla valutazione delle espressioni proposte e il risultato effettivo. Il primo caso appare risolto, come esempio:

Espressione Tipo che dovrebbe avere il risultato dell'espressione
4+((double) 3)
(double) 7
(int) (4.4+4.9)
 
 
 
(double) 4/3
 
 
 
((double) 4)/3
 
 
 
4 * ((long int) 3)
 
 
 

744.7   Espressioni multiple

Un'istruzione, cioè qualcosa che termina con un punto e virgola, può contenere diverse espressioni separate da una virgola. Tenendo presente che in C l'assegnamento di una variabile è anche un'espressione, la quale restituisce il valore assegnato, si veda l'esempio seguente:

int x;
int y;
...
y = 10, x = 20, y = x*2;

L'esempio mostra un'istruzione contenente tre espressioni: la prima assegna a y il valore 10, la seconda assegna a x il valore 20 e la terza sovrascrive y assegnandole il risultato del prodotto x·2. In pratica, alla fine la variabile y contiene il valore 40 e x contiene 20.

Un'espressione multipla, come quella dell'esempio, restituisce il valore dell'ultima a essere eseguita. Tornando all'esempio, visto, gli si può apportare una piccola modifica per comprendere il concetto:

int x;
int y;
int z;
...
z = (y = 10, x = 20, y = x*2);

La variabile z si trova a ricevere il valore dell'espressione y = x*2, perché è quella che viene eseguita per ultima nel gruppo raccolto tra parentesi.

A proposito di «espressioni multiple» vale la pena di ricordare ciò che accade con gli assegnamenti multipli, con l'esempio seguente:

y = x = 10;

Qui si vede l'assegnamento alla variabile y dello stesso valore che viene assegnato alla variabile x. In pratica, sia x che y contengono alla fine il numero 10, perché le precedenze sono tali che è come se fosse scritto: y = (x = 10).

744.7.1   Esercizio

Osservando i pezzi di codice indicati, si scriva il valore contenuto nella variabile c. Il primo caso appare risolto, come esempio:

Codice Valore contenuto nella variabile c dopo l'esecuzione del codice mostrato
int a = -20;
int b = 10;
int c = (a *= 2, b += 10, c = a + b);
 
c contiene -20.
 
int a = -20;
int b = 10;
int c = (b = 2, b = a, c = a + b);
 
 
 
int a = -20;
int b = 10;
int c = (b = 2, b = a++, c = a + b);
 
 
 
int a = -20;
int b = 10;
int c = (b = 2, b = ++a, c = a + b);
 
 
 

744.7.2   Esercizio

Scrivere diversi programmi per verificare l'esercizio precedente. Viene proposto un esempio, riferito al caso iniziale risolto:

#include <stdio.h>
int main (void)
{
    int a = -20;
    int b = 10;
    int c = (a *= 2, b += 10, c = a + b);
    printf ("c contiene %d\n", c);
    getchar ();
    return 0;
}

1) Gli operandi di ? : sono tre.

2) Lo standard prevede il tipo di dati _Bool che va inteso come un valore numerico compreso tra zero e uno. Ciò significa che il tipo _Bool si presta particolarmente a rappresentare valori logici (binari), ma ciò sempre secondo la logica per la quale lo zero corrisponde a Falso, mentre qualunque altro valore corrisponde a Vero.


Appunti di informatica libera 2008 --- Copyright © 2000-2008 Daniele Giacomini -- <appunti2 (ad) gmail·com>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome operatori_ed_espressioni_del_linguaggio_c.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home]

Valid ISO-HTML!

CSS validator!

Gjlg Metamotore e Web Directory