logo

Compilation d'un programme C : dans les coulisses

La compilation est le processus de conversion du code source du langage C en code machine. Comme C est un langage de niveau intermédiaire, il a besoin d’un compilateur pour le convertir en code exécutable afin que le programme puisse être exécuté sur notre machine.

Le programme C passe par les phases suivantes lors de la compilation :



processus de compilation en c

Processus de compilation en C

Comment compiler et exécuter un programme C ?

Nous avons d’abord besoin d’un compilateur et d’un éditeur de code pour compiler et exécuter un programme C. L'exemple ci-dessous concerne une machine Ubuntu avec le compilateur GCC.

Étape 1 : Création d'un fichier source C

Nous créons d’abord un programme C à l’aide d’un éditeur et enregistrons le fichier sous filename.c



classe vs objet en Java
  $ vi filename.c>

Nous pouvons écrire un simple programme Hello World et le sauvegarder.

Étape 2 : Compilation à l’aide du compilateur GCC

Nous utilisons la commande suivante dans le terminal pour compiler notre fichier source filename.c

  $ gcc filename.c –o filename>

Nous pouvons transmettre de nombreuses instructions au compilateur GCC pour différentes tâches telles que :



  • L'option -Wall active tous les messages d'avertissement du compilateur. Cette option est recommandée pour générer un meilleur code.
  • L'option -o est utilisée pour spécifier le nom du fichier de sortie. Si nous n'utilisons pas cette option, un fichier de sortie portant le nom a.out est généré.

S'il n'y a aucune erreur dans notre programme C, le fichier exécutable du programme C sera généré.

Étape 3 : Exécution du programme

Après la compilation, l'exécutable est généré et nous exécutons l'exécutable généré à l'aide de la commande ci-dessous.

pause java
  $ ./filename>

Le programme sera exécuté et la sortie sera affichée dans le terminal.

Que se passe-t-il dans le processus de compilation ?

Un compilateur convertit un programme C en exécutable. Il y a quatre phases pour qu'un programme C devienne un exécutable :

    Liaison d'assemblage de compilation de prétraitement

En exécutant la commande ci-dessous, nous obtenons tous les fichiers intermédiaires du répertoire courant ainsi que l'exécutable.

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

La capture d'écran suivante montre tous les fichiers intermédiaires générés.

Fichiers intermédiaires

javafx

Voyons un à un ce que contiennent ces fichiers intermédiaires.

1. Prétraitement

Il s'agit de la première phase par laquelle le code source passe. Cette phase comprend :

  • Suppression des commentaires
  • Extension des macros
  • Extension des fichiers inclus.
  • Compilation conditionnelle

La sortie prétraitée est stockée dans le nom de fichier.i . Voyons ce qu'il y a à l'intérieur de filename.i : en utilisant $vi nom de fichier.i

paramètre dans le script shell

Dans la sortie ci-dessus, le fichier source est rempli de nombreuses informations, mais au final, notre code est préservé.

  • printf contient maintenant a + b plutôt que add(a, b) car les macros se sont développées.
  • Les commentaires sont supprimés.
  • #include est manquant à la place, nous voyons beaucoup de code. Les fichiers d'en-tête ont donc été étendus et inclus dans notre fichier source.

2. Compilation

L'étape suivante consiste à compiler filename.i et à produire un fichier ; fichier de sortie compilé intermédiaire nom de fichier.s . Ce fichier se trouve dans les instructions au niveau de l'assembleur. Voyons ce fichier en utilisant $nom de fichier nano.s commande du terminal.

Fichier de code d'assemblage

L'instantané montre qu'il est en langage assembleur, que l'assembleur peut comprendre.

3. Assemblage

Dans cette phase, le nom de fichier.s est pris en entrée et transformé en nom de fichier.o par l'assembleur. Ce fichier contient des instructions au niveau de la machine. A cette phase, seul le code existant est converti en langage machine et les appels de fonctions comme printf() ne sont pas résolus. Visualisons ce fichier en utilisant $vi nom de fichier.o

ensemble de textes dactylographiés

Code binaire

4. Lien

Il s'agit de la phase finale au cours de laquelle tous les liens entre les appels de fonction et leurs définitions sont effectués. Linker sait où toutes ces fonctions sont implémentées. Linker effectue également un travail supplémentaire, il ajoute du code supplémentaire à notre programme qui est requis au démarrage et à la fin du programme. Par exemple, un code est requis pour configurer l'environnement, comme transmettre des arguments de ligne de commande. Cette tâche peut être facilement vérifiée en utilisant $size nom de fichier.o et $size nom de fichier . Grâce à ces commandes, nous savons comment le fichier de sortie passe d'un fichier objet à un fichier exécutable. Cela est dû au code supplémentaire que Linker ajoute à notre programme.

Note: GCC effectue par défaut des liaisons dynamiques, donc printf() est lié dynamiquement dans le programme ci-dessus. Reportez-vous à this , this et this pour plus de détails sur les liens statiques et dynamiques.