{"id":101,"date":"2025-03-26T14:14:04","date_gmt":"2025-03-26T14:14:04","guid":{"rendered":"https:\/\/blog.nanuq.me\/?p=101"},"modified":"2025-03-26T14:14:04","modified_gmt":"2025-03-26T14:14:04","slug":"que-se-passe-t-il-lorsque-vous-tapez-gcc-main-c","status":"publish","type":"post","link":"https:\/\/blog.nanuq.me\/?p=101","title":{"rendered":"Que se passe-t-il lorsque vous tapez gcc main.c ?"},"content":{"rendered":"<p>Savez-vous ce qui se passe exactement lorsque vous utilisez un compilateur C comme <em>gcc<\/em> ?<\/p>\n<p><!--more--><\/p>\n<h1>Disclaimer<\/h1>\n<p>Pendant ma formation, je devais \u00e9crire des articles techniques. Ici, c&rsquo;est l&rsquo;article que j&rsquo;ai \u00e9cris \u00e0 propos de\u00a0 <code>gcc<\/code>. Il s&rsquo;agit d&rsquo;une traduction de la version r\u00e9dig\u00e9e en anglais, langue requise dans le cadre de la formation.<\/p>\n<h1>Bonjour \u00e0 tous.<\/h1>\n<p>J&rsquo;ai r\u00e9cemment commenc\u00e9 une formation pour changer de carri\u00e8re et devenir d\u00e9veloppeur. Cette formation consiste, bien s\u00fbr, \u00e0 apprendre \u00e0 coder, mais aussi \u00e0 communiquer avec d&rsquo;autres personnes et, en particulier, \u00e0 r\u00e9diger de la documentation technique. Dans cette optique, je r\u00e9dige un article de vulgarisation. Cet article doit \u00eatre con\u00e7u de mani\u00e8re \u00e0 \u00eatre compr\u00e9hensible m\u00eame par un d\u00e9butant.<\/p>\n<p>C&rsquo;est pourquoi, bien que nous aborderons des cas sp\u00e9cifiques et des concepts techniques assez avanc\u00e9s, je ne vais pas entrer dans tous les d\u00e9tails et je ferai quelques raccourcis. L&rsquo;objectif est d&rsquo;aller \u00e0 l&rsquo;essentiel et de se concentrer sur ce qui est vraiment important \u00e0 comprendre.<\/p>\n<h1>D\u00e9finitions<\/h1>\n<p>Socrate aurait dit :<\/p>\n<blockquote><p>\u201cLe d\u00e9but de la sagesse est la d\u00e9finition des termes.\u201d<\/p><\/blockquote>\n<p>Commen\u00e7ons donc par quelques d\u00e9finitions afin de bien comprendre dans quoi nous nous engageons :<\/p>\n<h2>GCC<\/h2>\n<p><strong>GGC<\/strong> signifie <strong>GNU Compiler Collection<\/strong>. Il s&rsquo;agit d&rsquo;un ensemble de compilateurs permettant de compiler divers langages de programmation tels que C, C++ et Java, pour n&rsquo;en citer que quelques-uns (dans cet article, nous nous concentrerons principalement sur le langage C). Cette d\u00e9finition, bien que utile, nous oblige \u00e0 examiner deux autres d\u00e9finitions. La premi\u00e8re est celle du <em>compilateur<\/em> et la seconde, celle du <em>langage C<\/em>.<\/p>\n<h2>Langage C<\/h2>\n<p>Le <a href=\"https:\/\/fr.wikipedia.org\/wiki\/C_(langage)\">langage C<\/a> a \u00e9t\u00e9 cr\u00e9\u00e9 en 1972 par <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Dennis_Ritchie\">Dennis Ritchie<\/a> et <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Brian_Kernighan\">Brian Kernighan<\/a>. Ce langage a permis de r\u00e9diger le syst\u00e8me d&rsquo;exploitation UNIX (rien que \u00e7a !).<\/p>\n<p>En fait, la fin des ann\u00e9es 60 marque le d\u00e9but de l&rsquo;informatique, et les syst\u00e8mes d&rsquo;exploitation commencent \u00e0 \u00eatre \u00e9crits. Pour r\u00e9diger ces syst\u00e8mes, on \u00e9crit des instructions envoy\u00e9es aux processeurs des ordinateurs. Ces instructions sont r\u00e9dig\u00e9es dans un langage que les puces peuvent comprendre : <strong>l&rsquo;assembleur<\/strong> (souvenez-vous-en, nous en reparlerons plus tard).<\/p>\n<p>Cependant, ce langage n&rsquo;est pas tr\u00e8s pratique \u00e0 utiliser, d&rsquo;abord parce que sa syntaxe est assez abstraite et \u00e9loign\u00e9e du langage humain ; et ensuite, parce que chaque processeur parle son propre langage, il faut donc adapter ce code assembleur d\u00e8s qu&rsquo;on veut le faire fonctionner sur une autre machine.<\/p>\n<p>Voici un exemple entre C et l&rsquo;assembleur :<\/p>\n<p><a href=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/c_vs_assembly-1-1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"size-large wp-image-106 aligncenter\" src=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/c_vs_assembly-1-1024x588.png\" alt=\"\" width=\"700\" height=\"402\"><\/a><\/p>\n<p>C&rsquo;est pourquoi des langages comme C ont \u00e9t\u00e9 cr\u00e9\u00e9s. Non seulement pour avoir une syntaxe qui ressemble davantage au langage humain, mais aussi pour pouvoir porter le code que nous \u00e9crivons. En fait, on peut convertir le m\u00eame code \u00e9crit en C pour une machine A qui n&rsquo;utilise pas le m\u00eame processeur qu&rsquo;une machine B. C&rsquo;est ce qu&rsquo;on appelle un compilateur, et la transition est parfaite !<\/p>\n<h2>Compilateur C<\/h2>\n<p>Un compilateur est un programme qui <em>traduit<\/em> le code source (dans ce cas, le code C) en un langage ex\u00e9cutable par la machine.<\/p>\n<h1>Comment fonctionne GCC<\/h1>\n<h2>Fonctionnement de base<\/h2>\n<p>Comme nous l&rsquo;avons vu plus t\u00f4t, nous comprenons d\u00e9sormais comment fonctionne un compilateur, et nous allons nous int\u00e9resser de plus pr\u00e8s \u00e0 un compilateur particulier : <strong>GCC<\/strong> (ou <strong>gcc<\/strong> dans le reste de l&rsquo;article, car les commandes sont souvent \u00e9crites en minuscules).<\/p>\n<p>Vous penseriez qu&rsquo;il suffit de donner un fichier \u00e9crit en C en entr\u00e9e (ce sont des fichiers avec l&rsquo;extension <em>.c<\/em>) et qu&rsquo;il en ressortira un code ex\u00e9cutable.<\/p>\n<p><a href=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/compilersimpleexemple-1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-105 size-full\" src=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/compilersimpleexemple-1.png\" alt=\"\" width=\"400\" height=\"140\"><\/a><\/p>\n<p>Mais en r\u00e9alit\u00e9, beaucoup de choses se passent en coulisses&#8230; Laissez-moi vous montrer ce qui se passe sous le capot !<\/p>\n<h2>Sous le capot&#8230;<\/h2>\n<p>Voici tout ce qui se passe sous le capot de gcc, et tout ce qu&rsquo;il fait en arri\u00e8re-plan dont nous ne savons m\u00eame pas qu&rsquo;il se passe ! Voyons cela \u00e9tape par \u00e9tape&#8230;<\/p>\n<p><a href=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/C-diagram.drawio-1-1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-104\" src=\"https:\/\/blog.nanuq.me\/wp-content\/uploads\/2025\/03\/C-diagram.drawio-1-1024x499.png\" alt=\"\" width=\"700\" height=\"341\"><\/a><\/p>\n<h3>\u00c9tape 0 &#8211; a : Fichiers sources<\/h3>\n<p>Imaginons que nous voulons compiler un fichier que j&rsquo;appelle <em>main.c.<\/em> Voici le code :<\/p>\n<pre><code>#include &lt;stdio.h&gt;\n\nint main(void)\n{\n    printf(\"Hello, World !\\n\");\n    return (0);\n}<\/code><\/pre>\n<p>C&rsquo;est ce qu&rsquo;on appelle le code source, c&rsquo;est-\u00e0-dire toutes les instructions n\u00e9cessaires \u00e0 l&rsquo;ex\u00e9cution de notre programme pour faire ce que l&rsquo;on veut. Ici, je veux afficher les mots <em><strong>\u201cHello World !\u201d<\/strong><\/em> \u00e0 l&rsquo;\u00e9cran (<a href=\"https:\/\/fr.wikipedia.org\/wiki\/&quot;Hello,_World!&quot;_program\">pourquoi est-ce toujours Hello World ?<\/a>). Pour compiler mon fichier, je dois taper la commande suivante :<\/p>\n<pre>gcc main.c<\/pre>\n<p>(Bien s\u00fbr, vous devrez adapter \u201cmain.c\u201d au nom de votre fichier&#8230; Cela s&rsquo;applique \u00e0 chaque fois que vous verrez \u201cmain.c\u201d dans le reste de cet article.)<\/p>\n<p><strong>Mais que se passe-t-il ensuite ?<\/strong><\/p>\n<h3>\u00c9tape 0 &#8211; b : Fichiers d&rsquo;en-t\u00eate<\/h3>\n<p>Avant de regarder ce qui se passe avec notre <em>main.c,<\/em>, nous devons aussi savoir qu&rsquo;il existe des fichiers appel\u00e9s <strong>en-t\u00eates<\/strong>.<\/p>\n<p>Ces fichiers indiquent toutes les fonctions que nous voulons rendre disponibles pour d&rsquo;autres fichiers. C&rsquo;est comme un index pour savoir rapidement les <em>ingr\u00e9dients<\/em> dont nous aurons besoin dans notre code, sans avoir \u00e0 passer par tout le code pour savoir ce dont nous avons besoin. Ils permettent aussi de structurer et de partager des d\u00e9finitions entre plusieurs fichiers sources et facilitent la gestion de projets \u00e0 grande \u00e9chelle en \u00e9vitant de r\u00e9p\u00e9ter plusieurs fois les m\u00eames choses dans plusieurs fichiers. Pour simplifier, <strong>je ne l&rsquo;ai pas inclus dans cet exemple<\/strong>, mais ce type de fichier existe bien.<\/p>\n<h3>\u00c9tape 1 &#8211; Pr\u00e9processeur<\/h3>\n<p><strong>Le pr\u00e9traitement<\/strong> est la toute premi\u00e8re \u00e9tape r\u00e9alis\u00e9e par le compilateur. C&rsquo;est une sorte de pr\u00e9paration pour le reste des t\u00e2ches. Typiquement, dans l&rsquo;exemple pr\u00e9c\u00e9dent, nous voyons que nous utilisons <em>#include<\/em>. En d&rsquo;autres termes, nous voulons utiliser une biblioth\u00e8que de fonctions existante. Le pr\u00e9processeur va alors r\u00e9cup\u00e9rer le contenu de la biblioth\u00e8que et l&rsquo;inclure dans notre code, pr\u00eat \u00e0 \u00eatre compil\u00e9. Le pr\u00e9processeur supprimera \u00e9galement les commentaires afin de ne pas interf\u00e9rer avec le reste du processus et prendra en charge d&rsquo;autres t\u00e2ches (comme la gestion de <em>#define<\/em>), mais ce n&rsquo;est pas le sujet de cet article et cela m\u00e9riterait un article \u00e0 part.<\/p>\n<p>Si vous ne demandez rien de particulier \u00e0 <strong>gcc<\/strong>, ces t\u00e2ches sont r\u00e9alis\u00e9es de mani\u00e8re invisible. Cependant, si vous voulez voir ce qui se passe \u00e0 la fin de cette \u00e9tape de pr\u00e9traitement, tapez la commande suivante pour g\u00e9n\u00e9rer ces fichiers pr\u00e9trait\u00e9s au format `.i` et arr\u00eater la compilation apr\u00e8s cette t\u00e2che :<\/p>\n<pre>gcc -E main.c<\/pre>\n<h3>\u00c9tape 2 &#8211; Compilateur<\/h3>\n<p>Vient ensuite le <strong>compilateur<\/strong>. Le compilateur prend le code source (apr\u00e8s qu&rsquo;il ait \u00e9t\u00e9 nettoy\u00e9 par le pr\u00e9processeur) et le traduit en langage assembleur, qui est une repr\u00e9sentation textuelle de ce que sera le futur code machine. Il v\u00e9rifie \u00e9galement qu&rsquo;il n&rsquo;y a pas d&rsquo;erreurs dans le code (erreurs de syntaxe, ou fonctions mal utilis\u00e9es). Si des erreurs sont d\u00e9tect\u00e9es, <strong>gcc<\/strong> nous les signale pour que nous puissions les corriger. Plut\u00f4t sympa, non ?<\/p>\n<p>Encore une fois, la g\u00e9n\u00e9ration et l&rsquo;utilisation de ces fichiers `.s` sont cach\u00e9es, et si vous voulez les afficher, tapez :<\/p>\n<pre>gcc -S main.c<\/pre>\n<h3>\u00c9tape 3 &#8211; Assembleur<\/h3>\n<p>Nous arrivons maintenant \u00e0 l&rsquo;\u00e9tape de l&rsquo;<strong>assembleur<\/strong>. Cette \u00e9tape prend les fichiers d&rsquo;assembleur vus \u00e0 l&rsquo;\u00e9tape 2 et les convertit en code machine (c&rsquo;est-\u00e0-dire en code binaire) dans un format que le processeur peut ex\u00e9cuter. Les fichiers ainsi cr\u00e9\u00e9s sont des fichiers objets se terminant par <em>.o<\/em>.<\/p>\n<p>Comme pr\u00e9vu, ces fichiers sont g\u00e9n\u00e9r\u00e9s et utilis\u00e9s de mani\u00e8re invisible, et si vous souhaitez les afficher, utilisez la commande :<\/p>\n<pre>gcc -c main.c<\/pre>\n<p><strong>Si vous avez suivi, nous avons mentionn\u00e9 le langage assembleur au d\u00e9but de cet article. Eh bien, avant l&rsquo;invention du C, les d\u00e9veloppeurs devaient coder directement en assembleur, et c&rsquo;est exactement ce type de fichier que l&rsquo;\u00e9tape de l&rsquo;assembleur cr\u00e9e dans GCC. Rien n&rsquo;est laiss\u00e9 au hasard !<\/strong><\/p>\n<h3>\u00c9tape 4 &#8211; \u00c9diteur de liens<\/h3>\n<p>Nous arrivons maintenant \u00e0 l&rsquo;\u00e9tape finale. Comme indiqu\u00e9 dans notre diagramme, l&rsquo;assembleur cr\u00e9e plusieurs fichiers objets <em>.o<\/em>. Bien que ces fichiers soient en langage machine, et que l&rsquo;assembleur soit capable de les lire ind\u00e9pendamment les uns des autres, il ne peut pas les lier entre eux. C&rsquo;est l\u00e0 qu&rsquo;intervient l&rsquo;<strong>\u00e9diteur de liens<\/strong> : il r\u00e9unit ces diff\u00e9rents fichiers <em>.o<\/em> en un seul fichier ex\u00e9cutable complet. Il peut \u00eatre utilis\u00e9 pour r\u00e9soudre les r\u00e9f\u00e9rences (si, par exemple, des fichiers objets font r\u00e9f\u00e9rence \u00e0 des fonctions d\u00e9finies dans d&rsquo;autres fichiers, comme <em>printf<\/em> dans notre exemple). Il fait le lien entre les biblioth\u00e8ques, connectant les bonnes fonctions et variables aux bons endroits dans le programme.<\/p>\n<h3>\u00c9tape 5 &#8211; Notre fichier ex\u00e9cutable !<\/h3>\n<p>Si tout s&rsquo;est bien pass\u00e9 et que GCC ne nous a pas signal\u00e9 d&rsquo;erreurs, notre commande a g\u00e9n\u00e9r\u00e9 un fichier `a.out` (le nom du fichier g\u00e9n\u00e9r\u00e9 par d\u00e9faut) et nous pouvons l&rsquo;ex\u00e9cuter pour afficher fi\u00e8rement notre \u201cHello World !\u201d.<\/p>\n<pre>gcc main.c<\/pre>\n<h1>Et maintenant ?<\/h1>\n<p>Bien que ce soit un langage ancien, le C est toujours largement utilis\u00e9 aujourd&rsquo;hui. Pourquoi ? D&rsquo;abord parce qu&rsquo;il est le \u201cp\u00e8re\u201d de tous les langages modernes. Des langages comme Python, C++, Java, Javascript et Perl ont tous \u00e9t\u00e9 influenc\u00e9s par ce langage, donc conna\u00eetre le C permet d&rsquo;acqu\u00e9rir une certaine logique et de rapidement prendre en main ces langages plus modernes. Ensuite, en utilisant le C, il y a tr\u00e8s peu d&rsquo;\u00e9tapes et d&rsquo;interm\u00e9diaires entre les instructions du code et leur ex\u00e9cution par le processeur. Cela permet de mieux ma\u00eetriser l&rsquo;utilisation de la m\u00e9moire, du processeur et des temps d&rsquo;ex\u00e9cution, ce qui est tr\u00e8s utile pour coder des applications n\u00e9cessitant des performances \u00e9lev\u00e9es et des logiciels informatiques de base.<\/p>\n<h1>C&rsquo;est tout, les amis !<\/h1>\n<p>Merci d&rsquo;avoir lu cet article jusqu&rsquo;au bout, et n&rsquo;h\u00e9sitez pas \u00e0 commenter si vous avez des questions ou des remarques.<\/p>\n<p>\u00c0 bient\u00f4t pour de nouvelles aventures !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Savez-vous ce qui se passe exactement lorsque vous utilisez un compilateur C comme gcc ?<\/p>\n","protected":false},"author":1,"featured_media":102,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[28,38,59,77,95,117],"_links":{"self":[{"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/wp\/v2\/posts\/101"}],"collection":[{"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=101"}],"version-history":[{"count":0,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/wp\/v2\/posts\/101\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=\/"}],"wp:attachment":[{"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=101"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=101"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.nanuq.me\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=101"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}