Vantaggi della programmazione in linguaggio C++

La CPU riconosce un insieme di operazioni elementari per l'acquisizione, la memorizzazione, l'elaborazione dei dati e l'emissione dei risultati, quale ad esempio l'istruzione:

 

memorizza il valore 100 nella locazione di memoria avente indirizzo 12345

 

La programmazione a questo livello di dettaglio è molto scomoda: costringe il programmatore a gestire gli spazi di memoria e a esprimere un'operazione descrivendola nei termini che la CPU riconosce.

La programmazione in linguaggio C++ permette al programmatore di

  1. esprimere sinteticamente un comando. Sarà il compilatore a farsi carico di tradurlo nelle istruzioni che la CPU è in grado di eseguire (sinteticità);

  2. apportare modifiche e miglioramenti al programma agevolando l'individuazione delle istruzioni che devono essere revisionate (Manutenzione);

  3. Rendere il programma eseguibile da qualsiasi CPU (Portabilità).

Rispetto ad altri linguaggi di programmazione il C++ consente di utilizzare funzioni di basso livello allo scopo di giungere ad un programma ottimizzato sia in termini di spazio occupato sia in termini di tempo di esecuzione

Ottimizzazione del Programma

Il linguaggio C possiede poche istruzioni, ma molti operatori e molte funzioni.

Alcuni degli operatori corrispondono direttamente a un'istruzione macchina. Inoltre sono ammesse espressioni che permettono al compilatore di produrre un codice ottimizzato.


Esempi:
gli operatori di autoincremento e autodecremento hanno la corrispondente istruzione assembler: INC e DEC.
In un comune linguaggio di programmazione per incrementare una variabile bisogna usare un espressione come:
i = i + 1,
che il compilatore potrebbe tradurre con una sequenza di istruzioni come le seguenti:

MOV AX, valore della variabile i

ADD AX, 1

MOV variabile i, AX

Mentre in linguaggio C il compilatore traduce direttamente:

 

INC variabile i

 

In questo modo il programma è più compatto, ma anche più veloce. Infatti l'istruzione INC può essere lunga anche solo un byte (se l'operando si trova in un registro) e viene eseguita con il minimo numero di cicli di clock.


Tra le espressioni che il compilatore riconosce e sfrutta per ottimizzare il codice vi è l'assegnazione multipla.
Normalmente l'inizializzazione di variabili comporta un lungo elenco di assegnazioni del tipo:
a = 0
b = 0
c = 0
In linguaggio C, poichè l'operatore di assegnazione si comporta come una funzione, cioè restituisce il risultato dell'espressione a secondo membro, allora sono ammesse espressioni della forma:

 

a = b = c = 0

 

Anche in questo caso il compilatore produce una traduzione più compatta, della forma:

XOR AX, AX

MOV variabile a, AX

MOV variabile b, AX

MOV variabile c, AX

In ciascuna istruzione un operando è un registro contenente il valore da assegnare alle variabili, quindi le istruzioni sono lunghe al massimo 2 byte. In un altro linguaggio di programmazione, invece, il compilatore avrebbe prodotto istruzioni contenenti ciascuna lo stesso valore dell'operando, e quindi lunghe anche 3 byte.

Il procedimento di Compilazione

Dopo la fase di analisi del problema, l'individuazione dell'algoritmo risolutivo e la definizione delle strutture dati, il programmatore deve codificare il procedimento che risolve il problema in un linguaggio di programmazione. La produzione del programma, a questo punto, avviene in tre passi.

  1. Il programma viene scritto nel linguaggio di programmazione tramite un text editor. (programma sorgente)

  2. Il programma sorgente viene dato in input al compilatore che produce in output il programma oggetto.

  3. Il programma oggetto è la traduzione in linguaggio macchina del programma sorgente. Si deve considerare che la traduzione non consiste nel trasformare ciascuna istruzione dal linguaggio C al linguaggio macchina, perchè un'istruzione in linguaggio C esprime un'operazione complessa che potrebbe essere descritta mediante molte istruzioni in linguaggio macchina. Inoltre Il programmatore fa uso di istruzioni che non appartengono al linguaggio, ma sono disponibili in una libreria di funzioni (ad esempio le operazioni matematiche). Il terzo passo (collegamento o Linking) consiste nel collegare tutti i riferimenti che il compilatore non ha tradotto alle funzioni di libreria per produrre il programma eseguibile.

il compilatore, per svolgere la traduzione, compie un'analisi sintattica delle istruzioni (operazione di Parsing), che consiste nel riconoscere gli elementi che fanno parte dell'istruzione (codice operativo e operandi)

Alcuni linguaggi di programmazione (ad esempio il basic) sono detti interpretati perchè ciascuna istruzione del programma in formato sorgente viene tradotta e subito eseguita. Addirittura se il flusso del programma conduce nuovamente su un'istruzione già incontrata, l'interprete la traduce di nuovo, prima di eseguirla. Si nota che in un linguaggio interpretato la fase di esecuzione del programma dura molto di più a causa della continua traduzione delle istruzioni. In un linguaggio compilato, invece, la traduzione viene fatta una sola volta.

Il linguaggio C++ si basa sul linguaggio C per realizzare la programmazione orientata agli oggetti (OOP).

il programma Hello World

Si ricordi che il linguaggio C++ è case sensitive (distingue tra maiuscole e minuscole): la variabile unaVariabile è diversa dalla variabile unavariabile.

codifica

Avviare Dev Cpp e aprire un nuovo progetto di tipo "Console Application". Scrivere il seguente programma:

// il programma che saluta

#include <cstdlib>

#include <iostream>

int main(int argc, char *argv[]) {

  std::cout << "Hello World\n";

  system("PAUSE");

  return EXIT_SUCCESS;

}

Simboli del linguaggio

Gli elementi che vengono riconosciuti dal compilatore sono:

tipoDescrizioneEsempi
KeywordsTermini che hanno un significato per il compilatore int, double, for
Identificatorinomi, che non appartengono al linguaggio, scelti dal programmatore argc, argv, x, unaFunzione
Costanti (Literals)Valore specificato nell'istruzione "Hello world!", 24.3, 0, ‘c’
Operatorisegni per indicare operazioni matematiche o logiche +, -, &&, %, <<
Spazisegni usati nel text editor che vengono ignorati dal compilatore Spazi, tabulazioni, vai a capo

Descrizione del programma

Notare che, per indicare al compilatore la fine di un'istruzione e l'inizio della successiva, ogni istruzione è terminata con il punto e virgola. Infatti un'istruzione potrebbe occupare più linee. Oppure su una sola linea si possono inserire più istruzioni

Sezioni di un programma

un programma contiene:

Sia in una dichiarazione, sia in un'istruzione si possono formare delle espressioni usando gli operatori matematici:

Dichiarazioni del tipo dei dati

Il tipo di un dato è l'intervallo di valori che il dato può assumere e viene quindi espresso mediante il numero di bit che vengono riservati per rappresentare il valore.

TipoDescrizioneNr. bitRange
charUn solo carattere. Indicato tra singoli apici (‘a‘, ‘3‘). 1 byte signed: -128 to 127
unsigned: 0 to 255
int intero. 4 bytes signed: -2147483648 to 2147483647
unsigned: 0 to 4294967295
bool Boolean (true/false). Può assumere solo i valori true e false. 1 byte true (1) - false (0).
double numero in "Doppia" precisione. 8 bytes ±1.7e ±308 ( 15 digits)

Note:

Il risultato di un'operazione è un valore dello stesso tipo degli operandi. Quindi ad esempio 3/2 fornisce 1, perchè i due operandi sono interi. Per ottenere il risultato corretto bisogna esprimere i due operandi in notazione reale: 3.0/2.0;

Una stringa di caratteri viene dichiarata di tipo char *.

Variabili

Una variabile è il nome assegnato ad una locazione di memoria destinata a contenere un dato. Per esempio per fare dei calcoli con il valore 6 si memorizza il valore nella variabile x:

#include <iostream>

using namespace std;

int main () {

  int x;

  x = 6;

  cout << x / 3 << ' ' << x * 2;

  return 0;

}

Si noti che si può stampare una sequenza di valori concatenandoli con il simbolo <<

Gli identificatori possono contenere lettere, numeri e caratteri di sottolineatura, ma non devono cominciare con un numero. La linea int x è la dichiarazione della variabile x. Con essa si chiede al compilatore di riservare uno spazio sufficientemente grande per rappresentare un valore intero e di riferisi ad esso con il nome x.
La linea x = 6 è un'operazione di assegnazione: viene valutata l'espressione a secondo membro e il risultato viene scritto nella locazione identificata con x Le due linee potrebbero essere sostituite da:
int x = 4 + 2;
In questo caso l'assegnazione è detta inizializzazione.

Input

Il programma precedente svolge sempre le stesse operazioni sullo stesso valore, In generale il programma deve svolgere le stesse operazioni ma sui dati forniti in input.

#include <iostream>

using namespace std;

int main () {

  int x;

 

  cin >> x;

 

  cout << x / 3 << ' ' << x * 2;

  return 0;

 

}

Il doppio segno maggiore o minore nelle istruzioni di I/O viene detto operatore di scorrimento e il suo verso concorda con la direzione del trasferimento: dalla tastiera >> alla memoria (Input), dalla memoria << allo schermo (Output).

Errori

Gli errori possono essere segnalati dal compilatore quando non è stata rispettata la sintassi o possono essere riscontrati nei risultati diversi da quelli attesi. In questo caso il compilatore non è in grado di fornire assistenza perchè non riesce a fare l'analisi semantica delle istruzioni. Il programmatore deve adottare opportune tecniche di collaudo per verificare che il programma fornisca sempre risultati corretti per qualsiasi combinazione di dati di input venga data. In presenza di risultati sbagliati il programmatore deve poi riconoscere le istruzioni che provocano il comportamento imprevisto e correggerle.

Input/Output in C++

Il linguaggio C++ possiede gli stessi operatori e le stesse regole di scrittura delle dichiarazioni del linguaggio C. Qualsiasi cosa che si può fare in C può essere fatta in C++. Le caratteristiche che introduce il linguaggio C++ rappresentano un nuovo stile di programmazione che rispetta i principi della programmazione orientata agli oggetti (OOP: Object Oriented Programming).

Streams per Input e Output

Il termine stream, in informatica, ha il significato di flusso continuo e ordinato di dati e rappresenta il modello di un generatore di informazioni (byte) che li fa scorrere lungo un canale verso il ricevitore, dove vengono raccolti nel loro ordine di arrivo.

Osservando la versione C++ del programma che stampa "Hello World", chi conosce le operazioni di stampa in C, può notare che questo programma non include stdio.h ma include iostream.h, e non chiama printf per stampare una stringa, ma usa la variabile non dichiarata denominata cout, inoltre si vede anche l'operatore di scorrimento a sinistra e la stringa da mostrare.

Lo Stream di output

Per mostrare un messaggio sullo schermo:

cout "Hello, world\n";

La stringa Hello, wor1d\n viene inviata sullo schermo. l'operatore << (in C++) è chiamato operatore di scorrimento. È orientato dall'elemento che deve essere inviato (la stringa) al destinatario che lo deve acquisire (lo schermo).

Se anzichè stampare una stringa si volesse stampare un intero, in C si dovrebbe usare printf con il destrittore di formato relativo alla variabile da stampare:

printf( "%d", Numero);

In C++ non è necessario specificare il formato:

#include <iostream.h>

void main () {

  int Numero = 123;

  cout << Numero;

}

Il programma stampa 123.

Si può inviare qualsiasi tipo di dato predefinito sullo stream di output, non occorre specificare il formato. Lo stream cout riconosce il tipo della variabile e la stampa correttamente. Nell'esempio seguente si mostra come stampare una stringa, un intero e un carattere usando una sola istruzione.

void main () {

  int Numero = 123;

  cout << "valore di numero: " << Numero << endl;

}

Questo programma invia tre diversi tipi di variabili a cout: una stringa, la variabile intera Numero e il carattere endl per chiudere il messaggio con un vai a capo. Il programma stampa:

Valore di Numero: 123.

Notare che i diversi tipi sono separati dall'operatore <<.

Applicare il Formato all'Output

Si supponga di volere stampare il valore contenuto in una variabile intera secondo il codice esadecimale. Il linguaggio C++ associa dei manipolatori allo stream di output. Questi cambiano il formato di rappresentazione di default per gli interi. I nomi dei manipolatori sono dec, oct e hex. L'esempio che segue mostra come stampare un intero nella codifica ottale ed esadecimale:

void main () {

  int Numero = 123;

  cout << dec << Numero << ' '

        << oct << Numero << ' '

        << hex << Numero << endl;

}

Nelle istruzioni di stampa ognuno dei manipolatori (dec, oct e hex) converte il valore contenuto nella variabile intera Numero nelle 3 differenti rappresentazioni. Questo programma stampa:

 

123 173 7b

 

Ognuno dei valori stampati corrisponde allo stesso numero 123 decimale.


Lo stream di input

Per leggere dati immessi tramite la tastiera il linguaggio C++ mette a disposizione cin. Nel prossimo esempio si mostra come usare cin per leggere un dato intero da tastiera:

void main () {

  int Numero;

  cout << "Scrivi un numero: ";

  cin >> Numero;

  cout << endl << "il numero inserito e': " << Numero << endl;

}

In questo esempio si chiede di inserire un valore numerico da tastiera e cin lo trasferisce nella variabile Numero. L'istruzione di stampa mostra il valore contenuto nella variabile Numero usando cout.

Si può usare cin per leggere qualsiasi altro tipo di dato. L'esempio seguente mostra come leggere una stringa da tastiera:

void main () {

  int nome[20];

  cout << "Scrivi un nome: ";

  cin >> nome;

  cout << endl << "il nome inserito e': " << nome << endl;

}

L'array di caratteri, in cui memorizzare la stringa, è lungo solo 20 caratteri. Se si scrive un nome di lunghezza maggiore potrebbe verificarsi un errore, La funzione get risolve questo problema (consultare la guida alla libreria iostream). Per adesso si assuma che non verranno inseriti più di 20 caratteri.


Nota - Si ricordi che le funzioni di input e di output del C, scanf e printf non appartengono al linguaggio, ma sono funzioni di libreria. Analogamente gli stream cin e cout non appartengono al linguaggio C++, ma sono definite nella libreria iostream.h. Inoltre il significato degli operatori << e >> dipende dal contesto in cui vengono usati. Quando vengono usati con cout e cin consentono di scrivere o di leggere dati.


Commenti

In C++ è ammesso indicare i commenti usando sia la notazione del C, racchiudendo il commento tra la coppia di caratteri /* di inizio commento e la coppia di caratteri */ di fine commento, che con la notazione a doppio slash (//). Questa, però interpreta come commento tutto ciò che segue, fino alla fine della riga.

Prototipo di funzione

Una funzione può essere dichiarata prima di essere definita.

La dichiarazione specifica l'identificatore usato come nome della funzione, il tipo del valore di ritorno e il tipo dei parametri. La dichiarazione di funzione, che precede il suo uso è chiamata prototipo di funzione. Questo consente al compilatore di verificare se le chiamate di funzione rispettano il tipo dei parametri.

L'esempio che segue usa un prototipo di funzione per stampare i saluti:

// programma con il prototipo di funzione

void main () {

  mostra("Hello word");

}

 

void mostra(char *s) {

  cout << s;

}

Il prototipo di funzione non è necessario se la funzione viene definita prima di essere usata perchè la definizione agisce anche come prototipo. Il prototipo è necessario se la funzione viene definita in un file separato.