logo

Compilazione di un programma C: dietro le quinte

La compilazione è il processo di conversione del codice sorgente del linguaggio C in codice macchina. Poiché il C è un linguaggio di medio livello, necessita di un compilatore per convertirlo in codice eseguibile in modo che il programma possa essere eseguito sulla nostra macchina.

Durante la compilazione il programma C attraversa le seguenti fasi:



processo di compilazione in c

Processo di compilazione in C

Come compiliamo ed eseguiamo un programma C?

Per prima cosa abbiamo bisogno di un compilatore e di un editor di codice per compilare ed eseguire un programma C. L'esempio seguente è di una macchina Ubuntu con compilatore GCC.

Passaggio 1: creazione di un file sorgente C

Per prima cosa creiamo un programma C utilizzando un editor e salviamo il file come nomefile.c



ordinare un elenco di array
  $ vi filename.c>

Possiamo scrivere un semplice programma Hello World e salvarlo.

Passaggio 2: compilazione utilizzando il compilatore GCC

Usiamo il seguente comando nel terminale per compilare il nostro file sorgente filename.c

  $ gcc filename.c –o filename>

Possiamo passare molte istruzioni al compilatore GCC per diversi compiti come:



755 chmod
  • L'opzione -Wall abilita tutti i messaggi di avviso del compilatore. Questa opzione è consigliata per generare un codice migliore.
  • L'opzione -o viene utilizzata per specificare il nome del file di output. Se non utilizziamo questa opzione, verrà generato un file di output con il nome a.out.

Se non ci sono errori nel nostro programma C, verrà generato il file eseguibile del programma C.

Passaggio 3: esecuzione del programma

Dopo la compilazione, viene generato l'eseguibile ed eseguiamo l'eseguibile generato utilizzando il comando seguente.

  $ ./filename>

Il programma verrà eseguito e l'output verrà mostrato nel terminale.

differenza tra un gigabyte e un megabyte

Cosa c'è dentro il processo di compilazione?

Un compilatore converte un programma C in un eseguibile. Ci sono quattro fasi affinché un programma C diventi un eseguibile:

    Collegamento all'assieme di compilazione pre-elaborazione

Eseguendo il comando seguente, otteniamo tutti i file intermedi nella directory corrente insieme all'eseguibile.

  $gcc -Wall -save-temps filename.c –o filename>

Lo screenshot seguente mostra tutti i file intermedi generati.

File intermedi

Vediamo uno per uno cosa contengono questi file intermedi.

1. Pre-elaborazione

Questa è la prima fase attraverso la quale viene passato il codice sorgente. Questa fase comprende:

  • Rimozione dei commenti
  • Espansione delle macro
  • Espansione dei file inclusi.
  • Compilazione condizionale

L'output preelaborato viene archiviato nel file nomefile.i . Vediamo cosa c'è dentro nomefile.i: using $vi nomefile.i

Nell'output sopra, il file sorgente è pieno di tantissime informazioni, ma alla fine il nostro codice viene preservato.

  • printf ora contiene a + b anziché add(a, b) perché le macro si sono espanse.
  • I commenti vengono rimossi.
  • Manca #include invece vediamo molto codice. Quindi i file header sono stati espansi e inclusi nel nostro file sorgente.

2. Compilazione

Il passo successivo è compilare nomefile.i e produrre un; file di output compilato intermedio nomefile.s . Questo file si trova nelle istruzioni a livello di assembly. Esaminiamo questo file utilizzando $nano nomefile.s comando da terminale.

differenza tra ghiaccio e neve

File di codici di assieme

L'istantanea mostra che è in linguaggio assembly, che l'assemblatore può comprendere.

3. Assemblaggio

In questa fase il filename.s viene preso come input e trasformato in nomefile.o dall'assemblatore. Questo file contiene istruzioni a livello di macchina. In questa fase, solo il codice esistente viene convertito in linguaggio macchina e le chiamate a funzioni come printf() non vengono risolte. Visualizziamo questo file utilizzando $vi nomefile.o

quanto fa 10 su 100?

Codice binario

4. Collegamento

Questa è la fase finale in cui viene eseguito tutto il collegamento delle chiamate di funzione con le relative definizioni. Linker sa dove sono implementate tutte queste funzioni. Linker fa anche del lavoro extra, aggiunge del codice extra al nostro programma che è richiesto all'avvio e alla fine del programma. Ad esempio, esiste un codice richiesto per configurare l'ambiente come passare gli argomenti della riga di comando. Questa attività può essere facilmente verificata utilizzando $dimensione nomefile.o E nome file $dimensione . Attraverso questi comandi, sappiamo come il file di output aumenta da file oggetto a file eseguibile. Ciò è dovuto al codice aggiuntivo che Linker aggiunge al nostro programma.

Nota: GCC per impostazione predefinita esegue il collegamento dinamico, quindi printf() è collegato dinamicamente nel programma precedente. Fare riferimento a this , this e this per maggiori dettagli sul collegamento statico e dinamico.