GeeksforGeeks (Français)

Le C est un langage de niveau intermédiaire et il a besoin d’un compilateur pour le convertir en code exécutable afin que le programme puisse être exécuté sur notre machine.

Comment compiler et exécuter un programme C ?
Voici les étapes que nous utilisons sur une machine Ubuntu avec le compilateur gcc.

compilation

  • Nous créons d’abord un programme C à l’aide d’un éditeur et nous enregistrons le fichier sous le nom de nom de fichier.c
 $ vi filename.c
  • Le schéma de droite montre un programme simple pour additionner deux nombres.

compil31

  • Puis le compiler en utilisant la commande ci-dessous.
 $ gcc –Wall filename.c –o filename
  • 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 permet de spécifier le nom du fichier de sortie. Si nous n’utilisons pas cette option, alors un fichier de sortie avec le nom a.out est généré.

compil21

  • Après la compilation l’exécutable est généré et nous exécutons l’exécutable généré en utilisant la commande ci-dessous.
 $ ./filename 

Qu’est-ce qui se passe dans le processus de compilation ?
Le compilateur convertit un programme C en un exécutable. Il y a quatre phases pour qu’un programme C devienne un exécutable :

  1. Pré-traitement
  2. Compilation
  3. Assemblage
  4. Liaison

En exécutant la commande ci-dessous, nous obtenons tous les fichiers intermédiaires dans le répertoire actuel 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.

compil4

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

Pré-traitement

C’est la première phase par laquelle passe le code source. Cette phase comprend :

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

La sortie prétraitée est stockée dans le nom du fichier.i. Voyons ce qu’il y a à l’intérieur de filename.i : using $vi filename.i
Dans la sortie ci-dessus, le fichier source est rempli de beaucoup et beaucoup d’infos, mais à la fin notre code est préservé.
Analyse :

  • printf contient maintenant a + b plutôt que add(a, b) c’est parce que les macros ont été étendues.
  • Les commentaires sont dépouillés.
  • Le #include<stdio.h> est absent au lieu de cela nous voyons beaucoup de code. Ainsi, les fichiers d’en-tête ont été étendus et inclus dans notre fichier source.

Compilation

L’étape suivante consiste à compiler nomfichier.i et à produire un ; fichier de sortie compilé intermédiaire nomfichier.s. Ce fichier est en instructions de niveau assemblage. Voyons à travers ce fichier en utilisant $vi filename.s

image

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

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 de niveau machine. A cette phase, seul le code existant est converti en langage machine, les appels de fonction comme printf() ne sont pas résolus. Visualisons ce fichier en utilisant $vi nomfichier.o

compil7

Liaison

C’est la phase finale dans laquelle tous les liens des appels de fonctions avec leurs définitions sont faits. Linker sait où toutes ces fonctions sont implémentées. Linker fait aussi un travail supplémentaire, il ajoute du code supplémentaire à notre programme qui est nécessaire lorsque le programme commence et se termine. Par exemple, il y a un code qui est nécessaire pour configurer l’environnement comme passer des arguments de ligne de commande. Cette tâche peut être facilement vérifiée en utilisant $size filename.o et $size filename. Grâce à ces commandes, nous savons comment le fichier de sortie passe d’un fichier objet à un fichier exécutable. Ceci est dû au code supplémentaire que le linker ajoute avec notre programme.

compil8

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *