Résumé
Cette leçon explique ce qu’est un programme et ce que fait un compilateur : la machine n’exécute que des opérations élémentaires sur des nombres en mémoire, et le code source doit être traduit en code machine avant d’être exécuté. À l’aide d’un programme de deux fichiers, elle parcourt les trois étapes de cette traduction en C++ (prétraitement, compilation et édition de liens), et elle distingue ce qui se passe à la compilation de ce qui se passe à l’exécution, avec une erreur de chaque sorte. Elle compare les langages compilés aux langages interprétés, résume l’histoire de C++ jusqu’aux normes C++23 et C++26, et précise quel C++ enseigne ce cours.
Objectifs d’apprentissage
- Expliquer, à l’aide d’un schéma, le parcours d’un fichier source jusqu’à un exécutable : prétraitement, compilation et édition de liens, avec ce qui entre dans chaque étape et ce qui en sort.
- Classer un événement comme relevant de la compilation, de l’édition de liens ou de l’exécution, tel qu’une erreur de syntaxe, l’absence d’une fonction ou une division par zéro.
- Comparer un langage compilé à un langage interprété selon le moment où les erreurs sont détectées et ce que le programmeur voit de la machine.
- Situer dans le temps les normes du langage et expliquer pourquoi le cours utilise C++23.
Ce qu’est un programme
Un programme est une suite d’instructions qu’une machine peut exécuter pour transformer des données en résultats. Dans la leçon précédente, Du problème à l’algorithme, on a vu qu’avant le programme vient l’algorithme, la méthode qui résout le problème, écrite pour qu’une personne la suive. Le programme est cette même méthode écrite pour une machine, qui ne comprend ni phrases ni intentions, mais des ordres élémentaires : copier un nombre d’un endroit de la mémoire à un autre, additionner deux nombres, les comparer, sauter à une autre instruction selon le résultat.
La mémoire de l’ordinateur est une longue file de cases numérotées, chacune contenant un nombre de 0 à 255 (un octet). Tout ce que la machine manipule y est codé sous forme de nombres : les données et aussi les instructions elles-mêmes. S’il en est ainsi, un programme exécutable est une suite de nombres que le processeur interprète comme des ordres, le code machine, et il dépend du processeur : ceux de la famille x86-64, courants dans les ordinateurs de bureau, et les ARM, courants dans les téléphones et dans les Mac récents, ne comprennent pas les mêmes nombres.
Personne n’écrit aujourd’hui en code machine. On écrit dans un langage de haut niveau, comme C++, dont les instructions ressemblent à la notation mathématique, dans un fichier texte appelé code source (ou simplement source). Il s’ensuit la nécessité d’un traducteur qui produise, à partir de la source, le code machine équivalent : en C++, le compilateur.
Voici un programme complet en C++. Il n’est pas encore nécessaire de le comprendre : chacune de ses lignes sera expliquée dans la leçon 1.5. Il suffit de voir que c’est du texte, qu’il peut être lu, et qu’en dessous apparaît ce qu’il a écrit à l’exécution.
// Sera expliqué ligne par ligne dans la leçon 1.5.#include <print>int main(){ std::println("Bonjour, le monde"); std::println("2 + 3 = {}", 2 + 3);}Bonjour, le monde2 + 3 = 5Pour voir l’autre extrémité de la traduction, considérons une fonction qui ne fait qu’additionner deux entiers (les fonctions seront étudiées dans l’unité 5). Ce n’est pas un programme complet, car il lui manque main, le point où commence l’exécution, mais le compilateur peut la traduire à elle seule.
int add(int a, int b){ return a + b;}Le programme objdump montre le code machine que GCC 15 a produit pour elle sur un ordinateur x86-64 sous Linux : sur chaque ligne, la position de l’instruction, ses octets en hexadécimal et son nom lisible.
$ g++ -std=c++23 -O1 -c add.cpp$ objdump -d add.o0000000000000000 <_Z3addii>: 0: f3 0f 1e fa endbr64 4: 8d 04 37 lea (%rdi,%rsi,1),%eax 7: c3 retL’addition entière s’est réduite à huit octets. La première instruction, endbr64, est une marque de sécurité qui ne calcule rien ; la deuxième, lea, additionne les deux nombres que la fonction a reçus dans deux registres du processeur (%rdi et %rsi) et laisse le résultat dans un troisième (%eax) ; la troisième, ret, revient au point d’où la fonction a été appelée. Le nom _Z3addii est la manière dont le compilateur code « fonction add à deux paramètres int ».
Deux observations découlent de l’exemple. Premièrement : le code machine ne conserve ni les noms a et b, ni l’indentation, ni les commentaires ; tout cela existait pour qui lit la source, et le compilateur s’en est servi pour décider quelles instructions écrire. Deuxièmement : ce qu’écrit le programmeur C++ se traduit en peu d’instructions et sans intermédiaires ; cette proximité de la machine est la raison de l’efficacité de C++ et, comme on le verra dans le cours, aussi de certains de ses dangers.
Chargement du contenu…