05 2 integrali-conversioni-costanti-preproc-inclusione

69
Introduzione al C++ Tipi integrali, conversioni di tipo, costanti ed espressioni costanti, direttive al preprocessore, inclusione condizionale

description

 

Transcript of 05 2 integrali-conversioni-costanti-preproc-inclusione

Page 1: 05 2 integrali-conversioni-costanti-preproc-inclusione

Introduzione al C++

Tipi integrali, conversioni di tipo, costanti ed espressioni costanti,

direttive al preprocessore, inclusione condizionale

Page 2: 05 2 integrali-conversioni-costanti-preproc-inclusione

2

Il concetto di tipo• Determina i valori che può assumere una variabile e le operazioni

ammissibili su di essa• Determina la memoria minima necessaria per memorizzare una

variabile• int: di solito una parola; float: di solito due parole

• Permette al compilatore di rilevare errori nell'uso delle variabili– un linguaggio è fortemente tipizzato se garantisce:

• correttezza delle istruzioni rispetto al tipo degli operandi, verificabile dal compilatore

• che non sorgano errori di tipo in esecuzione

• Il C++ persegue la tipizzazione forte– però è al tempo stesso molto permissivo, poiché ammette molte

conversioni automatiche tra tipi diversi

Page 3: 05 2 integrali-conversioni-costanti-preproc-inclusione

Il sistema dei tipi del C++

• Uno degli obiettivi principali del C++ è permettere al programmatore di creare tipi personalizzati e usarli come se fossero offerti dal linguaggio

• Il sistema dei tipi del C++ comprende– Tipi predefiniti (predefined)– Tipi composti (composite) – Tipi definiti dall’utente (user defined)– Tipi classe (class types)

Page 4: 05 2 integrali-conversioni-costanti-preproc-inclusione

Cosa c’è da sapere di ogni tipo

• Che valori ammette• Come sono rappresentati i valori nel calcolatore– Sarebbe bello ignorarlo, ma talvolta non si può

• Come rappresentare valori (costanti) di quel tipo nel programma (anche detti "literal")

• Come dichiarare e inizializzare variabili di quel tipo• Quali operazioni sono ammesse sulle variabili• Quali tipi sono “affini”– Sono definite conversioni automatiche tra tipi affini

Page 5: 05 2 integrali-conversioni-costanti-preproc-inclusione

Inizializzazione delle variabili• Le variabili si dichiarano e inizializzano– La dichiarazione definisce il tipo– L’inizializzazione definisce il valore iniziale della

variabile neonata– L’inizializzazione NON è l’assegnamento• quest’ultimo definisce il valore corrente della variabile• Alcune cose che si possono fare durante

l’inizializzazione sono vietate nell’assegnamento

int i = 0;

tipo identificatore inizializzatore

Page 6: 05 2 integrali-conversioni-costanti-preproc-inclusione

Inizializzazione di default (tipi predefiniti)

• Una variabile dei tipi predefiniti priva di inizializzatore viene inizializzata per default

• Il valore di default dipende dal tipo della variabile e dalla posizione della dichiarazione– Variabili dei tipi predefiniti definite al di fuori di una

funzione ricevono per default il valore 0– Variabili dei tipi predefiniti definite all'interno di una

funzione sono uninitialized, cioè il valore NON è definito• NB: per le variabili di tipo classe, il valore di

inizializzazione per default può essere specificato dal programmatore

Page 8: 05 2 integrali-conversioni-costanti-preproc-inclusione

I tipi predefiniti del C++

• I tipi aritmetici: integral e floating point

Page 9: 05 2 integrali-conversioni-costanti-preproc-inclusione

Il tipo bool• Sta per Boolean (booleano)• Rappresentare il tipo delle espressioni che il

programma usa per prendere decisioni (se…, fintantoché…)

• Ammette solo due valori: true e false– false è rappresentato tramite il valore numerico 0– true è rappresentato da qualunque valore numerico

diverso da 0bool b = true; // b vale truebool b = 23; // b vale truebool b = false; // b vale falsebool b = 0; // b vale false

• In altre parole bool è un tipo (affine a) intero!

Page 10: 05 2 integrali-conversioni-costanti-preproc-inclusione

10

Il tipo char• Ammette come valore un singolo carattere• Utilizza il minimo numero di bit necessario a rappresentare

l’insieme dei caratteri standard del calcolatore un byte (di solito 8 bit per rappresentare i caratteri ASCII)

• I caratteri sono rappresentati internamente da numeri interi e quindi tra essi è definito un ordinamento– Esempio: il carattere '1' è rappresentato dall’intero 49, il carattere 'A' dall’intero 65, …• quindi, nell’ordinamento, risulta '1' 'A'

– Per le lettere è scelta una codifica tale per cui l’ordinamento dei codici coincide con l’usuale ordinamento alfabetico: 'A''B' ecc.• Lettere alfabeticamente adiacenti hanno codifiche adiacenti

– Negli insiemi più usati le maiuscole latine sono codificate “prima” delle minuscole• Quindi ad esempio 'A''a' ma anche 'Z''a'

Page 11: 05 2 integrali-conversioni-costanti-preproc-inclusione

Il concetto di insieme di caratteri• A differenza dei numeri

interi, i caratteri non hanno una rappresentazione “naturale” nel calcolatore

• La rappresentazione è convenzionale e si ottiene “numerando” i simboli dell’insieme dei caratteri che si vuole rappresentare

• Esistono molti insiemi di caratteri, che coprono un numero differente di simboli di lingue diverse

• Gli insiemi di caratteri e le codifiche più usati sono– ASCII– ISO/IEC 8859– UNICODE con UTF-8 e

UTF-16

Page 12: 05 2 integrali-conversioni-costanti-preproc-inclusione

Why character encoding matters

http://en.wikipedia.org/wiki/Mojibake

Page 13: 05 2 integrali-conversioni-costanti-preproc-inclusione

Insieme di caratteri ASCII

• Lo American Standard Code for Information Interchange (ASCII ) è una codifica dei caratteri basata sull’alfabeto inglese che copre 27= 128 caratteri

• Usa 7-bit• 95 caratteri stampabili: i numeri 0-9, le lettere a-z e A-

Z, simboli di punteggiatura e lo spazio bianco• Vari caratteri non stampabili, tra cui alcuni codici di

controllo derivanti dalle Teletype machines

Page 14: 05 2 integrali-conversioni-costanti-preproc-inclusione

ASCII Table

Page 15: 05 2 integrali-conversioni-costanti-preproc-inclusione

ISO 8859 (ISO LATIN)• I 95 caratteri ASCII stampabili

sono sufficienti per lo scambio di informazioni in lingua inglese

• Molte altre lingue che usano l'alfabeto latino hanno bisogno di simboli addizionali, come la ß (tedesco), la ñ (spagnolo), la å (svedese e altre lingue scandinave) o le lettere accentate italiane (à, è, é, ì, ò, ù)

• L'ISO 8859 utilizza l'ottavo bit del byte, che permette la codifica di altri 128 caratteri

• ISO 8859 è organizzato in diverse parti: es: ISO 8859-1, Latin-1 Western European

http://en.wikipedia.org/wiki/ISO/IEC_8859

Page 16: 05 2 integrali-conversioni-costanti-preproc-inclusione

UNICODE, UTF-8, UTF-16• Unicode è un insieme di caratteri

e una sistema di codifica che comprende oltre 110.000 simboli

• Unicode si sovrappone a ISO/IEC 8859-1, ma codifica inoltre i caratteri di quasi tutte le lingue vive e in alcune lingue morte, nonché simboli matematici e chimici, cartografici, l'alfabeto Braille, ideogrammi ecc.

• I caratteri Unicode sono rappresentati con le codifiche UTF-8 e UTF-16

• UTF-8 (8-bit Unicode Transformation Format) è una codifica dei caratteri Unicode – usa un byte per i caratteri

dell’insieme ASCII, che hanno lo stesso codice sia UTF-8 sia in ASCII, e fino a 4 bytes per gli altri caratteri (codifica a lunghezza variabile)

• UTF-16 (16-bit Unicode Transformation Format) è una codifica dei caratteri Unicode – può rappresentare fino a

1,112,064 entità (code points) tra cui i caratteri UNICODE da 0 a 0x10FFFF

– La codifica è a lunghezza variabile, con uno o due unità da 16 bit

Page 17: 05 2 integrali-conversioni-costanti-preproc-inclusione

I tipi int

• Approssima il dominio degli interi• Normalmente utilizza 1 parola di memoria• Esistono anche le varianti – short int, long int e long long int– tipico: long 32 bit, long long 64 bit, short 16 bit,

e int 16 o 32 (per cui spesso int è grande quanto long int)

• Lo standard del C++ richiede che – spazio per short <= spazio per int <= spazio per long

<= spazio per long long

Page 18: 05 2 integrali-conversioni-costanti-preproc-inclusione

La gestione del segno• TUTTI i tipi integral, tranne bool, ammettono la

versione “senza segno” (unsigned)• Il tipo normale permette di rappresentare numeri

interi positivi e negativi• Il tipo unsigned permette di rappresentare solo

numeri interi positivi, ma utilizza un bit in più (e quindi può rappresentare di più valori)– unsigned int: un valore intero positivo di almeno 16

bit, compreso tra 0 e 216-1 – Il prefisso signed si può omettere – unsigned èquivale a unsigned int– unsigned char da 0 a 255

Page 19: 05 2 integrali-conversioni-costanti-preproc-inclusione

Rapporto tra tipi signed e unsigned

• Tipi signed e unsigned non andrebbero mescolati • Se si assegna un valore fuori intervallo a una variabile

di tipo unsigned, il risultato è definito come:– Il resto della divisione del valore per il massimo intero che

il tipo unsigned può rappresentare • Per esempio, un tipo unsigned char da 8-bit

rappresenta valori da 0 a 255. • L’assegnamento di un valore fuori intervallo dà come

esito il resto di tale valore diviso per 256 – Assegnare –1 a un unsigned char da 8 bit produce il valore

255!

Page 20: 05 2 integrali-conversioni-costanti-preproc-inclusione

Check this outint main() { // Assegna a unsigned valore negativo

unsigned char c; // va da 0 a 255;cout << "Inserire un numero negativo: " << endl;int i;cin >> i;cout << "Valore inserito (intero originale): " << i << endl;c=i; // assegno numero negativo a variabile charcout << "Valore inserito (char): " << c << endl;i=c; // recupero il valore intero di ccout << "Valore inserito (intero dopo la conversione a char): " << i << endl;return 0;

}

• Il compilatore non può rilevare l’errore• Non sa predire che valore inserisce l’utente• NB:

Page 21: 05 2 integrali-conversioni-costanti-preproc-inclusione

Rapporto tra char e int

• In molti linguaggi di programmazione, char e int sono tipi non solo diversi, ma incompatibili

• C e C++ considerano i caratteri come “una particolare interpretazione” dei numeri interi

• La convertibilità tra char e int può portare a programmi difficili da comprendere

• Usare char solo quando serve davvero una variabile che contenga un carattere, per esempio per– Cercare/contare/sostituire tutte le occorrenze di un

carattere in un testo

Page 22: 05 2 integrali-conversioni-costanti-preproc-inclusione

Da char a int• Determinare il codice di una lettera minuscola• Cosa serve– Una variabile char– Una variabile int

• Algoritmo1.Leggi il prossimo carattere2.Se è una lettera maiuscola

1. Convertilo in un intero2. Stampa il risultato della conversione3. Torna al punto uno

3.Termina

Page 23: 05 2 integrali-conversioni-costanti-preproc-inclusione

Da char a int

int main() { // Legge un carattere e stampa il codice ASCII char c; // se è una minuscola; altrimenti termina int i; cout << "Scrivi un car. minuscolo (maiusc. x finire)" << endl; cin >> c; while (c >= 'a' && c <= 'z') { // minuscolo? i = c; // assegna il valore del carattere a un intero cout << "Valore ASCII per " << c << " è" << i << endl; cout << "Scrivi car. minuscolo (maiusc. x finire)" << endl; cin >> c; } return 0; // termina}

NB: notare la ripetizione delle istruzioni che richiedono l'input

Page 24: 05 2 integrali-conversioni-costanti-preproc-inclusione

Iterazione e condizione• while (c >= 'a' && c <= 'z') {.. Corpo del ciclo..}

• Se la condizione è vera• esegue le istruzioni all’interno del corpo

• Quando la condizione è falsa • termina il ciclo (esce dal ciclo)

• (c >= 'a' && c <= 'z') • Esprime la condizione di permanenza nel ciclo• E’ un’espressione con valore di tipo bool, cioè vero o falso• && Operatore logico AND• ‘a’ è un valore costante (literal) di tipo carattere

Page 25: 05 2 integrali-conversioni-costanti-preproc-inclusione

Da int a charint main() { // Stampa il codice carattere char c; // corrispondente ai 128 codici ASCII for (int i=0; i<128; ++i) { c = i; // assegna il valore intero al carattere cout << "Il carattere corrispondente a " << i << " è: " << c << endl; } return 0;}

Page 26: 05 2 integrali-conversioni-costanti-preproc-inclusione

Iterazione a conteggio

• for (int i=0; i<128; ++i)• Quando una iterazione deve essere svolta un

numero preciso di volte si può usare un “ciclo for” • Il ciclo incrementa una variabile apposita (contatore)

per tener traccia del numero di interazioni – int i=0; dichiarazione del contatore– i<128; condizione di permanenza– ++i avanzamento del contatore

Page 27: 05 2 integrali-conversioni-costanti-preproc-inclusione

Ciclo while e ciclo forchar c;for (int i=0; i<128; i++) { c = i; cout << “Il carattere corrispondente a " << i << " è: " << c << endl; }

int i = 0;char c; while (i<128) { c = i; cout << “Il carattere corrispondente a " << i << " è: " << c << endl; i++;}

Page 28: 05 2 integrali-conversioni-costanti-preproc-inclusione

28

I tipi float e double

• Approssimano i numeri razionali• I valori si possono rappresentare con due notazioni– 315.779– 3.73E-5

• double di solito occupa più memoria di float– tipicamente 4 byte per float e 8 byte per double

• (...esistono anche i long double, che devono occupare almeno tanto spazio quanto i double)

• Lo standard prescrive la precisione minima, cioè il minimo numero di cifre significative

Page 29: 05 2 integrali-conversioni-costanti-preproc-inclusione

Come rappresentare valori dei tipi predefiniti

• Il valore 10 ha un tipo diverso da 10.0• 10L è un valore di tipo long int

Page 30: 05 2 integrali-conversioni-costanti-preproc-inclusione

Cautele

• Attenzione ai confronti tra floatfloat a, b;...if (a == b) ...

• non ha senso, a causa delle approssimazioni nella memorizzazione!! diff = A - B;

if ((diff < EPSILON) && (-diff < EPSILON));

• EPSILON costante definita in std::numeric_limits

Page 32: 05 2 integrali-conversioni-costanti-preproc-inclusione

Quali tipi scegliere

• Usare tipi unsigned quando si è certi che servono solo valori positivi

• Usare int per valori aritmentici (short di solito non basta)

• Se servono valori molto grandi usare long long• Non usare char e bool in espressioni aritmentiche

– Se proprio proprio serve un intero piccolo usare signed char o unsigned char

• Usare double per le operazioni in virgola mobile (di solito float ha precisione insufficiente e le operazioni sui double sono comunque veloci)

Page 33: 05 2 integrali-conversioni-costanti-preproc-inclusione

Conversioni di tipo

• Se un operando non è del tipo atteso e il compilatore non ha informazioni sul tipo desiderato interviene una conversione automatica di tipo– È detta anche cast implicito– Si opera la conversione anziché segnalare l'errore

• A volte è accompagnata da un “avvertimento” (warning)

• Esempio– int i; float f;– la valutazione dell’espressione i + f effettua prima la

conversione di i in float e poi la somma

Page 34: 05 2 integrali-conversioni-costanti-preproc-inclusione

La "scaletta" delle conversioni

Page 35: 05 2 integrali-conversioni-costanti-preproc-inclusione

Conversioni di tipo: esempi

int n, m; float x,y; n = 3.541 + 3; // il risultato è 6!

x n; // n da “int” è promosso a “float”x n x; // n è promosso a “float” e poi sommato a xn x; // x è troncato, ne sopravvive la parte interan n m;// il risultato della divisione tra interi è interon n x;/* n è convertito in “float”, poi si esegue la divisione, il risultato è troncato a int */x n x;//come sopra ma il risultato resta floatx n m;// attenzione: la divisione tra int tronca

Page 36: 05 2 integrali-conversioni-costanti-preproc-inclusione

Conversioni con il tipo bool

• Il tipo bool ha valore true o false• I valori interi vengono convertiti a bool come segue– 0 viene convertito a false– ogni altro valore intero viene convertito a true

• Vale anche la conversione inversa (promozione a int)bool b=false; int i; // inizializzazione

i = b; // i vale 0

b=true;

i = b; // i ora vale 1!

Page 37: 05 2 integrali-conversioni-costanti-preproc-inclusione

Conversioni con tipi un/signed

• Ecco perché è meglio non mescolareunsigned u = 10;

int i = -42;

cout << i + i << endl; // prints -84

cout << u + i << endl; // if 32-bit ints, prints 4294967264

• Il valore di i (-42) viene convertito a unsigned prima dell’addizione

unsigned u1 = 42, u2 = 10;

cout << u1 - u2 << endl; // ok: result is 32

cout << u2 - u1 << endl; // ok: but the result is… ?

Page 38: 05 2 integrali-conversioni-costanti-preproc-inclusione

Quando avvengono le conversioni automatiche

• Nelle espressioni, i valori di tipi aritmetici piccoli vengono solitamente promossi a intchar c, int i; i=c+i; // da evitare

• Nelle condizioni, tipi non bool sono convertiti a bool– while (33) equivale a while (true) !

• Nell’inizializzazione, il valore dell’inizializzatore è convertito al tipo della variabile inizializzata– int i = 3.14; // i inizializzato a 3 !

• Nelle espressioni aritmetiche, gli operando sono convertiti a un tipo comune

• Nelle chiamate di funzione (che vedremo)

Page 39: 05 2 integrali-conversioni-costanti-preproc-inclusione

Altri esempibool b = 42; // b is true

int i = b; // i has value 1

i = 3.14; // i has value 3

double pi = i; // pi has value 3.0

// assuming 8-bit chars

unsigned char c = -1; // c has value 255

Page 40: 05 2 integrali-conversioni-costanti-preproc-inclusione

Conversione (cast) esplicita

• Quando una conversione utile non verrebbe eseguita, la si può richiedere esplicitamente

• Es: divisione tra interi con risultato double x (double) n m;

• ES: troncamento esplicito del risultato cout << (int) x y;

• C++11 introduce una sintassi più precisa

Page 41: 05 2 integrali-conversioni-costanti-preproc-inclusione

ATTENZIONE

• Il cast (implicito o esplicito che sia) non modifica il tipo della variabile o delle variabili coinvolte, ma solo il tipo associato al valore dell'espressione

• Le variabili in memoria continuano a essere del tipo dichiarato staticamente nella parte dichiarativa del programma

• Il cambio del tipo della variabile può portare al cambio del valore dell’espressione dove la variabile è usata

Page 42: 05 2 integrali-conversioni-costanti-preproc-inclusione

Le espressioni

• Espressione: applicazione di operatori a operandi – Ha un valore e un tipo– Condizione: espressione con tipo booleano

• Cosa bisogna sapere sulle espressioni1. Ordine di valutazione2. Proprietà degli operandi (precedenza,

associatività)3. Tipo degli operatori e del risultato, conversioni

Page 43: 05 2 integrali-conversioni-costanti-preproc-inclusione

Espressioni base

Le espressioni base si compongono di:• Variabili– Il tipo è noto in base alla dichiarazione, e NON cambia

• Valori (detti anche costanti o literal)– Il tipo è deducibile da come sono “scritte”

• 3 : int (il più piccolo tra int, long, long long in cui il valore ci sta)

• 03 : int in notazione ottale• 0x3 : int in notazione esadecimale • 3.0 : float• 3.0L : long• '3' : char• "3" : stringa (sequenza di caratteri di lunghezza variabile)

Page 44: 05 2 integrali-conversioni-costanti-preproc-inclusione

Constanti di tipo stringa

"Hello World!" // string literal•Ha un tipo composto che vedremo in seguito– Array di const char

•Il compilatore appende al valore un carattere speciale "terminatore" ('\0')•La dimensione reale del valore è 1 + la dimensione apparente (c'è anche il carattere "terminatore")•Attenzione: "a" ha tipo e dimensione diversi da 'a'

Page 45: 05 2 integrali-conversioni-costanti-preproc-inclusione

Espressioni e operatori• Operatori unari: sia applicano a un operando– -2

• Operatori binari: sia applicano a due operandi– a+b

• Il valore di un'espressione dipende da precedenza e associatività degli operatori e può dipendere dall'ordine di valutazione delle sotto-espressioni– Quanto vale : 5 + 10 * 20/2 ?

• Nella valutazione intervengono anche le conversioni di tipo

Page 46: 05 2 integrali-conversioni-costanti-preproc-inclusione

Precedenza e associatività• Un'espressione con due o più operatori di dice composta• La sua valutazione richiede di assegnare gli operandi agli operatori• Si usano le regole di precedenza tra operatori diversi e le regole di

associatività per operatori con la stessa precedenza– Precedenza: 3+4*5 vale 23, non 35– Associatività: 20-15-3 vale 2, non 8 (associatività a sinistra)

• Le parentesi possono cambiare le regole– (3+4)*5 vale 35– 20-(15-3) vale 8

• Non solo operatori aritmetici:– cin >> v1 >> v2; // read into v1 and then into v2– L'operatore >> è associativo a sinistra– Il valore dell'espressione cin >> v1 è cin !– Equivale a (cin >> v1) >> v2;

Page 47: 05 2 integrali-conversioni-costanti-preproc-inclusione

Ordine di valutazione operandi• In generale l'ordine di valutazione di sotto-espressioni con

la stessa priorità NON è definito– int i = f1() + f2(); // f1, f2 sono funzioni

• Non si sa quale tra le funzioni f1() e f2() venga valutata per prima

• Non si devono fare ipotesi indebite– int i = 0;– cout << i << " " << ++i << endl; // undefined– ++i espressione che incrementa i e "torna" il nuovo valore– Potrebbe stampare 1 1 oppure 0 1 o qualsiasi altra cosa

• Ci sono 4 operatori per cui invece è stabilito l'ordine di valutazione delle sotto-espressioni– AND logico (&&) OR logico (||) operatore condizionale (? :),

operatore virgola (,)

Page 48: 05 2 integrali-conversioni-costanti-preproc-inclusione

Operatori aritmetici

• Precedenza e associatività (tutti associativi a sinistra)• PS: % indica il resto delle divisione tra due interi– Se m e n sono interi e n è diverso da 0,

• (m/n)*n + m%n = m– Non si applica a tipi in virgola mobile

precedenza

Page 49: 05 2 integrali-conversioni-costanti-preproc-inclusione

Operatori logici e relazionali

• Sono usati per costruire condizioni, cioè espressioni con valore di tipo bool

precedenza

Page 50: 05 2 integrali-conversioni-costanti-preproc-inclusione

La regola del cortocircuito• Gli operatori AND e OR in C e C++ hanno un ordine di

valutazione prefissato (a differenza delle pure espressioni della logica)– Prima l’operando di sinistra POI quello di destra

• Vale una regola detta del cortocircuito che evita di valutare inutilmente l’operando di destra– AND: se l’operando di sinistra vale false– OR: se l’operando di sinistra vale true

• La regola del corto circuito ha applicazioni interessanti, per esempio quando si ispezionano sequenze di dati (lo vedremo in seguito)

Page 51: 05 2 integrali-conversioni-costanti-preproc-inclusione

L’operatore di assegnamento• Anche = è un operatore!• L’operando di sinistra deve essere una variabile (più

precisamente un lvalue), quello di destra un’espressione (più precisamente un rvalue)

• Modifica lo stato del programma: assegna il valore dell’operando di destra all’operando di sinistra– i=3 è un’espressione, il cui valore è l’operando di sinistra, cioè i!– i=3; è un’istruzione! Per via del ;– L’operatore = è associativo a destra– x=y=3 equivale a x=(y=3)

• Si assegna il valore 3 a y, il risultato dell’espressione è y• Si effettua l’assegnamento x=y che copia il valore di y in x, anche x vale 3

• L’inizializzazione NON è un assegnamento (mai ribadito abbastanza)

Page 52: 05 2 integrali-conversioni-costanti-preproc-inclusione

Esempiint i = 0, j = 0, k = 0; // initializations, not

// assignment

1024 = k; // error: literals are rvalues

i + j = k; // error: arithmetic expressions are rvalues

k = 0; // result: type int, value 0

k = 3.14159; // result: type int, value 3

Page 53: 05 2 integrali-conversioni-costanti-preproc-inclusione

ATTENZIONE• Possiamo usare assegnamenti come condizioni e viceversa?• Si, perché = è un operatore, proprio come ==• Di solito però… succede quando si sta commettendo un

errore...!– x = y == 3; // Assegna a x il valore 0 o 1 e non modifica– while ( 3 = x ) // Errore di sintassi (3 non è una variabile)

• Ma soprattutto...– while(x = 3) ... È SEMPRE VERO!!! (per ogni valore precedente di x)– while (x = 0) ... È SEMPRE FALSO!!! (per ogni valore precedente di x)– while (x = y) ... equivale a scrivere

• x = y; • while ( y != 0 ) ...

• Ancora peggio...– while (! (x = 0)) ... NON TERMINA MAI !!!!

Page 54: 05 2 integrali-conversioni-costanti-preproc-inclusione

I costruttori di tipi• A partire dai tipi predefiniti si possono creare

nuovi tipi, che aggiungono proprietà speciali ai tipi predefiniti– const– reference– pointer– array

• A questi si aggiungono costruttori di tipi definiti interamente dall'utente– class– struct (eredità del C, poco usato in C++)

Page 55: 05 2 integrali-conversioni-costanti-preproc-inclusione

Il qualificatore const• Talora serve definire una variabile che non cambi valore• Per farlo si premette const alla dichiarazione

– const int modelloauto 159; // tipo const int– const float pigreco 3.14159265; // tipo const

float

• Un tipo const è diverso dal corrispondente tipo base• Una variabile const

– Si dichiara e inizializza obbligatoriamente– Non ammette assegnamento

• int i = 42;• const int ci = i; // ok: the value in i is copied into ci• ci = 43; // error, no assignment• const int k; // error: k is uninitialized const• int j = ci; // ok: the value in ci is copied into j

Page 56: 05 2 integrali-conversioni-costanti-preproc-inclusione

Visibilità delle variabili const• const float pigreco 3.14159265;

• Il compilatore sostituisce pigreco con il valore associato

• Il compilatore deve conoscere il valore dell'inizializzatore

• Se il programma è diviso in più file, la variabile const viene (ri)definita in ciascun file

• Alternativamente, la variabile const può essere definita in un solo file e dichiarata come esterna nei file che ne fanno uso

Page 57: 05 2 integrali-conversioni-costanti-preproc-inclusione

extern const• Per definire una variabile const una sola volta, si usa la keyword

extern sia nella definizione che nelle dichiarazioni

// file_1.cc definisce e inizializza una variabile const extern const float pigreco = 3.14159265;

// file_1.hextern const float pigreco; // stessa const di file_1.cc

• file_1.cc definisce e inizializza pigreco. Siccome la dichiarazione comprende un inizializzatore è una definizione. Però, siccome pigreco è const, si specifica extern per farla usare in altri file.

• La dichiarazione in file_1.h è anch'essa extern. Significa che pigreco non è locale a tale file ma definita altrove

• Altri file possono includere il file file_1.h e importare la definizione di pigreco

Page 58: 05 2 integrali-conversioni-costanti-preproc-inclusione

Definizione di macro: #define• Esiste anche un altro modo di definire un valore una volta per tutte

– la direttiva #define• #define PIGRECO 3.141592

– #define è una direttiva al preprocessore (come #include)– Non è terminata dal punto e virgola

• una direttiva al precompilatore non è un’istruzione C++– Non causa allocazione di memoria

• PIGRECO è una "costante simbolica"– Il simbolo PIGRECO viene sostituito nel codice con il valore 3.14 …

prima che il programma sia compilato– Si dice che PIGRECO è una macro-definizione (o semplicemente una

MACRO)– Per convenzione, le costanti definite tramite macro sono interamente

maiuscole (es: TIPICA_COSTANTE)

Page 59: 05 2 integrali-conversioni-costanti-preproc-inclusione

Definizione di macro: #define

• #define MIGLIO 1609.34• #define YARDA 0.9144• Si possono costruire MACRO a partire da altre

MACRO, e una macro può anche usare uno o più parametri:– #define AREACERCHIO(X) (PIGRECO(X)(X)) – area AREACERCHIO(4);– Diventa area (3.141592(4)(4)); – ma è un valore fisso !!

Page 60: 05 2 integrali-conversioni-costanti-preproc-inclusione

Altre direttive al precompilatore

• Abbiamo già visto: #include <nome_libreria>

– Serve a richiamare librerie– comanda al preprocessore di leggere anche da un altro file

sorgente

• Altra direttiva usata frequentemente:#undef VERO

– Serve ad annullare la definizione di una MACRO– Da quel punto in poi la costante VERO non è più definita

Page 61: 05 2 integrali-conversioni-costanti-preproc-inclusione

Esempio di programma multifile/* File contenente funzioni di utilità sui cerchi

* dichiarazione e definizione di una costante

* riusabile : pigreco.cpp */

extern const float pigreco = 3.14159265;

float area(float r){

return r*r*pigreco;

}

float perimeter(float r){

return 2*r*pigreco;

}

Page 62: 05 2 integrali-conversioni-costanti-preproc-inclusione

File di intestazione della libreria/* File contenente solo le dichiarazioni delle

* funzioni di utilità sui cerchi

* e della costante riusabile: pigreco.h

* Usato dal compilatore per controllare la

* correttezza del programma */

extern const float pigreco;

float area(float r);

float perimeter(float r);

Page 63: 05 2 integrali-conversioni-costanti-preproc-inclusione

Programma principale#include <iostream>

#include "pigreco.h"

using namespace std;

int main() {

float radius;

cout << "Insert the value of the radius: " << endl;

cin >> radius;

cout << "Value of pigreco: " << pigreco << endl;

cout << "Perimeter of circle: " << perimeter(radius) << endl;

cout << "Area of the circle: " << area(radius) << endl;

return 0;

}

Page 64: 05 2 integrali-conversioni-costanti-preproc-inclusione

I tipi definiti dall'utente

• La ragione principale del successo di C++ è che consente di estendere il sistema dei tipi in modo assai potente

• La novità introdotta dal C++ è che i tipi definiti dall'utente si possono usare (quasi) come quelli predefiniti

Page 65: 05 2 integrali-conversioni-costanti-preproc-inclusione

Requisiti• Si vuole costruire un programma che gestisca le

vendite di libri• Ogni libro è caratterizzato da un codice ISBN• Il programma deve gestire per ogni libro il numero

totale di copie vendute, il ricavo totale e medio• L'utente inserisce sequenzialmente i dati di vendita per

i diversi libri, il programma aggrega i dati per ciascun codice ISBN e stampa il dato aggregato

• Deve quindi essere possibile:– Inserire e stampare i dati di un libro– Sommare più dati di vendita relativi allo stesso libro – Stampare i dati di vendita aggregati relativi a un libro

Page 66: 05 2 integrali-conversioni-costanti-preproc-inclusione

Progettazione• Inizializza il totale vendite a 0• Leggi dati 1° transazione e aggiorna il totale• Finché ci sono transazioni– Leggi un'altra transazione;– Se la transazione letta è dello stesso libro di prima

• sommala al totale corrente;– Altrimenti

• stampa il totale corrente; // è cambiato il libro• inizializza il totale corrente del nuovo libro coi dati della

transazione letta; • Stampa il totale di vendita dell'ultimo libro (perché

serve??)

Page 67: 05 2 integrali-conversioni-costanti-preproc-inclusione

Suddivisione del programma

• Un file di libreria (Sales_item.h) conterrà la definizione del tipo che rappresenta il dato di vendita: Sales_item

• Sales_item è un tipo classe, cioè un tipo definito dall'utente che comprende dati e operazioni relativi al dato di vendita

• Il programma principale (Booksales.cpp) importa e usa Sales_item come se fosse un tipo predefinito– Sales_item item; // dichiara una var. di tipo Sales_item !

Page 68: 05 2 integrali-conversioni-costanti-preproc-inclusione

Un primo esempio di main()#include <iostream>

#include "Sales_item.h"

int main()

{

Sales_item book;

// read ISBN, number of copies sold, and sales price

std::cin >> book;

// write ISBN, # of copies sold, total revenue, and average price

std::cout << book << std::endl;

return 0;

}

•book è trattata come una variabile di un tipo predefinito•Si applicano gli stessi operatori di I/O che a una variabile di tipo int•Gli operatori sono definiti nel tipo classe Sales_item

Page 69: 05 2 integrali-conversioni-costanti-preproc-inclusione

L'esempio completoint main()

{

Sales_item total; // variable to hold data for the next transaction

// read the first transaction and ensure that there are data to process

if (cin >> total) {

Sales_item trans; // variable to hold the running sum

// read and process the remaining transactions

while (cin >> trans) {

// if we're still processing the same book

if (total.isbn() == trans.isbn())

total += trans; // update the running total

else {

// print results for the previous book

cout << total << endl;

total = trans; // total now refers to the next book

}

}

cout << total << endl; // print the last transaction

} else {

// no input! warn the user

cerr << "No data?!" << endl;

return -1; // indicate failure

}

return 0;

}

if(cin >> x)while(cin >> x)

La condizione è soddisfatta se l'acquisizione dell'input non ha dato erroriPer terminare, basta premere CTRL-Z (carattere end of file)