Il processo di compilazione di un programma C è composto da diverse fasi: preprocessamento (preprocessing), compilazione (compilation), assemblaggio (assembling), collegamento (linking). Storicamente, questo schema ha permesso di separare le responsabilità tra gli strumenti e facilitare la manutenzione e la configurazione del processo di build.
Problema: Se non si comprende come funziona ciascuna fase, si possono incorrere in errori come "undefined reference", duplicazione di codice, bug non evidenti a causa di un uso scorretto delle macro, e problemi nel ridimensionamento del codice su più file.
Soluzione: È necessario comprendere che ogni fase esegue una funzione specifica: il preprocessore elabora le direttive #define, #include e altre; il compilatore traduce il codice sorgente C in assembly, l'assemblatore in codice macchina, e il linker unisce tutti i file oggetto e le librerie nel file eseguibile finale.
Esempio di codice:
Frammento di codice sorgente:
#include <stdio.h> #define PI 3.14 int main() { printf("%f\n", PI); return 0; }
Esempio di chiamata a gcc specificando esplicitamente le fasi:
gcc -E program.c # Preprocessamento gcc -S program.c # Compilazione (fino all'assembly) gcc -c program.c # Assemblaggio (fino al file oggetto) gcc program.o -o prog # Collegamento (linking)
Caratteristiche chiave:
Cosa fa la direttiva #include "file.h" durante la fase di compilazione?
#Include inserisce il contenuto del file direttamente nel punto di chiamata durante il preprocessamento, prima dell'inizio della compilazione. Se lo stesso file è incluso due volte, questo può portare a definizioni multiple di oggetti o errori di collegamento.
È sempre sufficiente la definizione di una funzione in un file per usarla in un altro?
No, è necessario dichiararla (prototipo) in un file di intestazione o almeno una dichiarazione extern. Altrimenti, potrebbero verificarsi errori come "implicit declaration of function" o "undefined reference" durante il collegamento.
È possibile utilizzare variabili dichiarate come static, da un altro file?
No. static limita la visibilità della variabile o della funzione al file corrente. Questo significa che tali simboli non sono visibili al linker in altri file oggetto.
Un principiante implementa una funzione con lo stesso nome in due file sorgente. Durante la fase di collegamento si verifica un errore strano "multiple definition of function".
Pro:
Contro:
Creazione di file .h solo per dichiarazioni, file .c per definizioni. Uso di #ifdef per proteggere i file di intestazione. Tutti i file sono collegati tramite il linker nel programma finale.
Pro:
Contro: