Guida Linguaggio C: Introduzione
30 Ottobre 2007 C
   





Introduzione

Il C è un linguaggio ad alto livello, un programma scritto in C non può essere eseguito direttamente dal processore. Per questo motivo è necessario tradurre il programma scritto in linguaggio C in un linguaggio comprensibile al processore e che possa essere eseguito da esso. Questo linguaggio è il cosiddetto linguaggio macchina.
Il processo di traduzione produrrà, a partire dal file (o dai file) costituente il programma C, un file binario direttamente eseguibile dal processore. Questo file binario avrà estensione .exe o .com in ambiente windows.
Per tradurre il file (o i file) C nel file binario eseguibile si seguirà un processo di compilazione costituito da diverse fasi. 

La Compilazione

La compilazione di un programma C avviene in diverse fasi
  • Preprocessing. Il preprocessore riceve in input il programma C (costituito da uno o più file), interpreta le direttive al preprocessore eventualmente presenti sostituendole con codice C appropriato, e rimuove i commenti presenti all'interno del programma. Il prodotto finale di questa fase sarà il programma C iniziale privo di direttive al preprocessore e di commenti, il programma sarà quindi costituito da solo codice C.

    Figura 1.
  • Compilazione. Il compilatore analizza il programma C controllando la eventuale presenza di errori (errori sintattici), in mancanza dei quali il programma C verrà tradotto in linguaggio assembler. Il compilatore quindi riceverà in ingresso il programma C privo di direttive al preprocessore e di commenti e, in mancanza di errori, produrrà un programma in assembler.
  • Assemblaggio. Il codice assembler ricevuto dalla fase precedente viene tradotto in codice oggetto "rilocabile" e verrà salvato in un file con estensione .o in unix/linux, o con estensione .obj in windows.

    Figura 2.
  • Linking. Il linker riceve il file oggetto (o i file oggetto) e li assembla in un unico file eseguibile. In windows avrà estensione .exe, in linux il file sarà chiamato per default a.out.

    Figura 3.
La compilazione di un file con gcc si ottiene tramite il comando gcc test.c -o test, a partire dal file test.c si produrrà il file eseguibile test, per eseguirlo si usa il comando ./test.
Nel caso in cui non venga specificato il nome del file eseguibile, ovvero nel caso di un comando come questo gcc test.c si produrrà il file eseguibile a.out, per eseguirlo si usa il comando ./a.out.
Da notare infine che gcc si aspetta un linea vuota al termine del file in mancanza della quale verrà generato un errore (warning: no newline at end of file).

Il Makefile

Nel caso in cui il programma sia costituito da più file può diventare fastidioso compilare file per file e mettere insieme tutto, si può allora inserire tutte le istruzioni sui passi da seguire nella compilazione in un particolare file, il makefile.
Il makefile è costituito da regole della seguente forma

  1. target : prerequisiti ...
  2. comandi
  3. ...

dove target è solitamente il nome del file generato da un programma, esempi di target sono i file eseguibili o i file oggetto. Il prerequisito è un file usato come input per creare il target (un target spesso dipende da diversi file). Un comando è una azione da eseguire. Una regola può avere più comandi, ciascuno su una riga diversa.
Un esempio di makefile è il seguente

Makefile
  1. test : main.o file.o
  2. cc -o test main.o file.o
  3. main.o : main.c def.h
  4. cc -c main.c
  5. file.o : file.c def.h
  6. cc -c file.c

Si produrrà il file eseguibile test a partire dai file c main.c e file.c e dal file header def. Il file target test avrà come prerequisiti i due file main.o e file.o, e il comando, azione da eseguire per ottenere il file target, sarà cc -o test main.o file.o. Analogamente il file target main.o avrà come prerequisiti i due file main.c e def.h, e il comando, azione da eseguire per ottenere il file target, sarà cc -c main.c, eccetera.
Una volta creato il makefile si usa il comando make per compilare il file (o i file) C e produrre l'eseguibile
make Makefile

Figura 4.
Nel makefile è anche possibile definire delle variabili che possono essere usate in ogni contesto: target, prerequisiti, comandi. Per sostituire una variabile con il corrispondete valore si usa la forma seguente $(var), dove var è la variabile. Ecco un altro esempio di makefile

Makefile
  1. compiler = gcc # compilatore da usare
  2. eseguibile = file
  3. oggetto = file.o
  4. $(eseguibile): $(oggetto)
  5. $(compiler) -o $(eseguibile) $(oggetto)
  6. %.o: %.c
  7. $(compiler) -o $*.o -c $*.c

in cui sono state definite 3 variabili: compiler, eseguibile e oggetto. La variabile compiler conterrà il nome del compilatore da utilizzare, eseguibile e oggetto conterranno il nome del file eseguibile risultante e il nome del file oggetto.
Sono poi presenti due regole, la prima per la produzione dell'eseguibile a partire dal file oggetto

  1. $(eseguibile): $(oggetto)
  2. $(compiler) -o $(eseguibile) $(oggetto)

la seconda per la produzione del file oggetto a partire dal file c

  1. %.o: %.c
  2. $(compiler) -o $*.o -c $*.c

da notare in quest'ultima regola la presenza del simbolo % che sta ad indicare "qualsiasi stringa".

I File Header

La gran parte dei programmi è costituita da più file. Questo significa che è possibile che alcune funzioni o variabili o costanti siano definiti in un file ma possano essere utilizzati in un altro.
Per poter utilizzare una variabile (funzione, costante, ...) in un programma (in un file del programma) è necessario che questa sia dichiarata.

 
Guida Linguaggio C