martedì 16 dicembre 2014

Modern C++ - Il primo progetto

Nel post precedente abbiamo focalizzato l'attenzione sul setup dei tool di sviluppo e di supporto che andremo ad utilizzare durante questo corso.

Era d'obbligo mostrare inizialmente un po' di codice sorgente C++ al fine di testare il funzionamento dell'ambiente di sviluppo sulla propria macchina.
Da oggi, invece, si inizia seriamente con il linguaggio di programmazione e con CMake per la configurazione dei progetti.

Listato C++

 

Il progetto generato automaticamente da QtCreator, come abbiamo visto, è risultato il seguente:
Questo piccolo programma scrive il testo "Hello World" nel terminale e poi si chiude.
Come viene realizzato questo? Per prima cosa, fondamentale per ogni progetto e/o linguaggio di programmazione, è la riusabilitá. Costanti (ad esempio, il valore di Pi greco) e funzioni vengono definite in file, denominati header files, che vengono importati successivamente. Questi files generalmente hanno estensione *.h, *.hpp, *.hxx (la scelta è a discrezione dello sviluppatore), ma in C++ esistono header files built-in che non richiedono una estensione esplicita.
Ad un header file, spesso ma non sempre (vedremo il perché in futuro), è associato un source file, con estensione *.cpp, *.cxx, che contiene l'implementazione delle definizioni contenute nell'header file associato.

Linea 1

Notiamo l'importazione dell'header <iostream> per mezzo della parola chiave #include.
Questa parola chiave invoca il preprocessore, un programma che si occupa di svolgere alcuni step prima che venga attivato il processo di compilazione del programma (ovvero la conversione da linguaggio C++ a linguaggio macchina). In questo caso, la direttiva
#include <iostream>

invoca il preprocessore che si occupa di cercare il file iostream ed importarne le definizioni (le funzioni e/o le costanti) in esso contenute.
In C++, le funzioni che lavorano con la gestione degli stream (vedremo nelle successive lezioni cosa significa) sono definite in questo particolare file e tra le quali troviamo cout ed endl, scritte al rigo 7 del nostro codice sorgente.
Se provate ad eliminare quindi il rigo 1 e provate ad eseguire la compilazione, vedrete che QtCreator genererá un errore relativo alla mancata definizione di queste due funzioni.

Linea 3

In C++ è possibile specificare un namespace. Un namespace serve a raccogliere, sotto un identico nome, funzioni, classi, variabili, in modo univoco, evitando fraintendimenti con altre dichiarazioni che potrebbero avere lo stesso nome e che quindi creerebbero un conflitto.
Ad esempio, cout in realtá è definito come std::cout (notare doppi ":"), ovvero si sta utilizzando la "funzione  cout del namespace std". La regola generale è quella di poter estendere un namespace con nuove funzioni, ma è proibito avere due funzioni con lo stesso nome e numero di argomenti all'interno dello stesso.
Se, per alcuni motivi, utilizzassimo librerie di terze parti che abbiano a loro volta una implementazione della funzione cout, allora il namespace costituirebbe un fattore discriminante,  permettendo di usare sia
std::cout << "Hello World" << std::endl;
sia, ad esempio, con namespace mio::,
mio::cout << "Hello World" << mio::endl;
Nel caso di questo primo programma, al fine di evitare di scrivere continuamente il prefisso std:: per ogni funzione, si puó utilizzare il comando
using namespace std; 
ovvero diciamo al compilatore di apporre in automatico il prefisso std:: a tutte le funzioni contenute in <iostream> che stiamo utilizzando.

Linea 5

Il punto di ingresso (o entry point) di ogni programma in C o C++ è la funzione main().  Questa funzione è la prima ad essere eseguita e contiene a sua volta chiamate a funzioni oppure ad operazioni da eseguire.
Una volta completate queste operazioni, allora la funzione main termina e il programma viene chiuso, riportando uno stato, che rappresenta il successo o l'insuccesso dello stesso programma. Lo stato viene indicato con un numero intero, dato che con la dichiarazione:
int main()
stiamo definendo una funzione main con zero argomenti (le parentesi sono vuote) e che restituisce come risultato un numero intero (int è un tipo di dato che sta per integer/intero).
Non è possibile scrivere un programma C/C++ senza la funzione main.

Linea 7

Come già accennato in precedenza, cout ed endl hanno a che fare con gli stream di dati. In particolare, cout consente di scrivere sullo stream uscita (di default, la riga di comando) il valore specificato dopo il simbolo "<<", in questo caso "Hello World", mentre endl si occupa di terminare la riga di testo e andare a capo (ovvero si esegue il CRLF).
Pertanto, questa linea puó esser tradotta in italiano come segue: "sullo stream di uscita (la riga di comando in questo caso), scrivi 'Hello World' e vai a capo".
In contrasto a cout, esiste cin, che consente invece di leggere un valore di input e salvarlo in una variabile. Vedremo come utilizzare gli stream in successivi post.

Linea 8

Come menzionato nella discussione relativa alla linea 5, la funzione main è prossima a terminare, riportando un valore integer come risulato finale dell'esecuzione. Poichè è andato tutto a buon fine, riportiamo il varole 0, che indica il successo dell'esecuzione. In caso di errori (come vedremo in seguito), possiamo definire stati che aiutano a segnalare i problemi che si verificano durante la normale esecuzione di un programma.

File CMake

Fin qui abbiamo descritto il significato del codice sorgente C++, ma QtCreator ha creato anche un altro file, il file CMakeLists.txt, che permette di configurare il nostro progetto utilizzando il tool CMake.
In questo caso, il file risulta molto semplice da comprendere: stiamo generando un progetto chiamato FirstProject (linea 1), che richiede come versione minima di CMake installata la 2.8 (linea 2).
La linea 3 permette di includere nel progetto tutti i file sorgente presenti nell'attuale directory in cui il file CMakeLists.txt è presente:
aux_source_directory(. SRC_LIST) 
permette di salvare nella variabile SRC_LIST tutti i file con estensione nota (*.h, *.cpp, ecc.), nel nostro caso solamente il file main.cpp.
Infine, la linea 4 si occupa di definire il programma eseguibile, con nome FirstProject, come è stato definito nella linea 1, utilizzando come sorgente i file contenuti nella variabile SRC_LIST, ovvero solo main.cpp.

CMake, a seconda della piattaforma e del compilatore rilevato, genera i file di progetto, definendo quindi i file di progetto, eventuali librerie di terze parti, eventuali configurazioni specifiche (flag per il compilatore, generazione di file *.deb, *.zip, *.msi) in base alle necessitá. Di pari passo con i problemi che affronteremo in C++, vedremo come configurare i file CMakeLists.txt (ce ne possono essere uno per ogni subdirectory), in modo da crearci un mini-framework che ci permetterá di utilizzare tutti i file che scriveremo per nuovi ed interessanti progetti.

Per oggi concludiamo qui e vi chiedo nuovamente un piccolo contributo di tempo per la compilazione del seguente questionario. Inoltre, se avete dubbi, opinioni, suggerimenti, potete contattarmi attraverso Google+, Twitter oppure via email.

A presto!

Nessun commento:

Posta un commento