Guida al C/C++
autore: BlackLight
xx/xx/xx
Struttura di un programma in C:
Un programma scritto in C ha una sua struttura particolare.
In primis, i file
sorgente, ossia i file che contengono il codice C
per il compilatore, hanno estensione
.c (a volte anche .cc, su
Linux). Ci sono poi i file
header (con estensione
.h), che
sono i file che contengono i prototipi per le funzioni (vedremo più
avanti cosa sono) e le variabili usate nel programma. Queste funzioni
vengono poi implementate nei file sorgenti (quelli con estensione .c).
Vedremo che, per usare funzioni di qualsiasi tipo in un programma C, è
necessario richiamare il file header che contiene le funzioni che si
vogliono usare tramite la direttiva
#include.
In ogni caso, i programmini contenuti in questo tutorial sono piuttosto
semplici, quindi c'entrano in un solo file sorgente (con estensione .c).
Abbiamo già detto nel paragrafo precedente che il C è un linguaggio
compilato:
questo vuol dire che, una volta scritto il file sorgente (o i files
sorgenti), occorre che questo venga passato al compilatore C assieme al
nome del file in cui si desidera piazzare l'output. Con GCC faremo:
gcc -o file_eseguibile file1.c file2.c ... filen.c
Ecco il compilatore cosa fa:
Per prima cosa esegue le direttive al preprocessore (quelle che iniziano
con
#, come
#include #define #if #endif #ifdef... alcune
le vedremo nel corso di questo tutorial).
Se non ci sono errori nei sorgenti, traduce il codice C contenuto nei
files sorgenti in linguaggio macchina (in quanto è questo l'unico
linguaggio davvero comprensibile al compilatore. In genere questo processo
genera un file
oggetto, con estensione
.o o
.obj,
dove viente piazzato il codice in LM), quindi esegue l'operazione di
linking,
ossia crea il file eseguibile vero e proprio.
Quasi tutti i linguaggio ad alto livello (Pascal, FORTRAN, COBOL...) sono
linguaggi compilati.
Il BASIC, il Perl e il Python sono invece linguaggi
interpretati:
ciò vuol dire che non è possibile creare un file eseguibile vero e
propio con questi linguaggi, ma, ogni volta che voglio eseguire un tale
algoritmo, devo ricorre ad un
interprete, ossia un programma che
traduce istantaneamente il codice ad alto livello in linguaggio macchina.
La via di mezzo è il Java: una volta scritto un programma in Java, ho
bisogno di compilarlo (ad esempio, con il comando
javac): da
questo processo ho un file con estensione
.class, scritto in un
linguaggio simile al linguaggio macchina ma che non è linguaggio
macchina! A questo punto posso eseguire il mio programma con l'interprete
Java, che esegue il codice contenuto nel file class. E' uno dei punti di
forza del Java, che lo ha reso portabile verso ogni piattaforma.
Ovviamente, i linguaggi compilati e interpretati hanno i loro pregi e
difetti.
Con un linguaggio compilato posso creare un file eseguibile vero e
proprio, totalmente indipendente dal linguaggio, ma la procedura di
precompilazione-compilazione-linkaggio è spesso molto lenta (soprattutto
quando si tratta di compilare programmi dotati di GUI, di interfaccia
grafica). Inoltre, il file eseguibile che ho ottenuto dalla compilazione
è ottimizzato per la macchina dove l'ho compilato, non per un'altra. In
poche parole, se compilo un file C su Linux, lo stesso file eseguibile non
funzionerà su Windows.
Un linguaggio interpretato, invece, permette di vedere in real-time se il
programma che si sta scrivendo contiene o no errori, senza a vviare la
procedura di compilazione. Inoltre, un listato scritto, ad esempio, in
Perl su un sistema Linux funzionerà anche se lo porto su un sistema
Windows, a patto che vi sia installato l'interprete Perl. Però questi
linguaggi hanno lo svantaggio di non creare un file eseguibile, ossia di
non creare un vero e proprio programma da eseguire facendo un doppio click
sopra.