Comme ça, vous voulez (apprendre à) programmer en C...

(Nhat Minh Lê (rz0) @ 2010-10-19 00:47:30)

Il y a une dizaine d’années, je commençai à programmer, et bientôt, je me mis au C. Ce fut le début d’une longue histoire… Une petite décennie plus tard, je fais toujours du C, et j’ai décidé de partager un peu tout ce que j’ai appris. Cette page s’adresse aux débutants, et aux moins débutants, ou juste aux curieux.

—rz0

La première partie disserte brièvement sur ce que l’on appelle aujourd’hui le langage C. C’est toujours bon à savoir, mais si cela vous ennuie, ce n’est pas non plus très important. Si vous êtes à la recherche de conseils pour bien commencer la programmation avec le langage C, la section Débuter avec le C est probablement celle qui vous intéresse !

Les troisième et quatrième sections traitent des outils disponibles et de l’usage du C dans divers environnements que je connais et qu’il me paraît pertinents de discuter.

Une mini-FAQ conclut ; elle s’adresse plus particulièrement aux curieux et répond, de manière totalement subjective, à un certain nombre de questions d’opinion.

Les liens donnés sur cette page pointent, pour la plupart, vers des ressources en anglais. Lorsqu’il s’agit de pages Wikipédia, il est aisé de trouver l’équivalent écrit en français (s’il existe). Dans d’autres cas, cela peut être plus délicat, voire impossible. Moi aussi, j’aime bien le français, mais le monde de l’information est ainsi fait… et il faut nous y faire !

Pour tout commentaire, critique, ou suggestion, c’est par ici, dans le billet associé !

Le C, quel C ?

Le C est un langage de programmation, de ceux que l’on ne présente plus; inventé dans les années 70, encore en usage un peu partout, et pas près de mourir. Mais sa longévité légendaire n’est pas sans avoir engendré une floppée de clones plus ou moins ressemblants, et son arbre généalogique va du frère de sang au cousin éloigné dont on se demande s’il n’a pas usurpé le nom de famille au passage.

Alors comme ça, vous voulez programmer en C. Mais quel C, au juste ? Le C est un langage normé par l’ISO, mais ce serait se mentir de penser que tout le monde respecte cette norme. Le C, tel qu’on le connait aujourd’hui, c’est une famille de dialectes, certes très proches, avec à son centre la norme ISO, du moins, une norme ISO. Car il y en a plusieurs, du moins plusieurs versions.

Et puis peut-être que par C, vous entendez en fait un mélange de C et de C++. Ou juste du C++ bridé. Beaucoup de gens vous diront que ce n’est vraiment pas une bonne idée ; ce qui pourrait sembler parfaitement logique, « le C++ est une presque-surcouche du C donc je peux utiliser les deux ensemble », ne dissimule que trop bien des différences philosophiques qui se reflètent dans les idées, les méthodes, et les bonnes pratiques qui sous-tendent une utilisation efficace et éclairée — c’est-à-dire en accord avec son temps :) — du langage.

Mais au fond, toutes ces différences sont-elles importantes pour un débutant ? Question légitime. Si vous parlez de différences entre C et C++, alors, certainement, oui. Si c’est entre dialectes, ou entre versions de la norme C, alors, probablement, non. Vous pouvez commencer votre apprentissage du C, un C ou un autre, sans trop vous soucier de ces détails, et le hasard des erreurs, des besoins, des questionnements, et des remarques de vos pairs vous enseignera les subtilités.

Le reste de cette page ne parle que de C. Si vous êtes arrivé ici en quête de C++, je ne peux que vous recommander de regarder du côté de l’ami alpounet et sa page sur comment bien débuter en C++.

C89 vs C99

Les deux versions majeures de la norme C sont, à l’heure actuelle, communément désignées sous les abréviations C89 et C99. Elles correspondent à la publication de la norme ANSI C de 1989 (ou ISO C de 1990) et la révision majeure ISO C de 1999. Il y a eu, après chaque norme, un certain nombre d’amendements, et dans le langage informel, ceux-ci sont comptés implicitement. Lorsque l’on parle de C89, on parle de C89 et ses amendements.

Pourquoi donc marquer une différence entre C89 et C99 ? La raison est tout à fait pragmatique. Dans la pratique, C89 est presque universellement pris en charge par les implémentations récentes du langage, tandis que l’on ne peut pas en dire autant de C99.

Pour une description des différences techniques, vous pouvez consulter, par exemple, la page Wikipédia dédiée à C99. Mais la vraie question est : « Faut-il utiliser C99 ? » Et la réponse est, bien entendu : « Ça dépend. » Cela dépend de vos besoins, et du gain que représente l’utilisation d’une fonctionnalité absente de C89. La troisième partie de cette page peut vous aider à vous faire une idée, selon vos objectifs.

Et POSIX dans tout ça ?

Vous avez peut-être également entendu parler de POSIX et de « C POSIX ». POSIX n’est pas, à proprement parler, une norme du langage C. C’est un document normatif pour les systèmes d’exploitation. Là où cela devient intéressant, c’est que POSIX construit ses interfaces autour du langage C. En d’autres termes, POSIX définit des extensions directes des fonctionnalités décrites dans la norme C ; celles-ci couvrent un grand nombre d’aspects des systèmes actuels, tels que la communication entre processus ou sur le réseau, l’accès aux systèmes de stockage, etc.

En ce sens, le C POSIX, c’est le C standard couplé avec les interfaces de programmation POSIX. Tous les systèmes ne prennent pas en charge POSIX (en particulier, Windows lui résiste). Encore une fois, vous pouvez vous référer à la troisième partie sur les implémentations du langage C, pour plus de détails.

Débuter avec le C

En autodidacte

Au fond, toutes ces petites différences ne vous effraient pas, et vous avez décidé de franchir le pas et de vous lancer. C’est bien ; j’aime beaucoup le C et je ne peux que vous encourager sur cette voie… et peut-être vous aider un peu.

Par où donc commencer ? Il y a probablement plus d’ouvrages et de ressources pour apprendre le C que n’importe quel autre langage, sur Internet comme en librairie. Alors que choisir ? Entre nous, je pense que cela n’a guère d’importance. Il y a quelques grands noms tels que le fameux « K&R », plus officiellement connu comme The C Programming Language, par Brian W. Kernighan et Dennis M. Ritchie, ce dernier étant le père du langage (pour ceux qui ne le sauraient pas). Certains le disent très bien, d’autres sont plus critiques ; je ne l’ai, pour ma part, que feuilleté. Mais il m’a paru tout a fait honnête.

Plus généralement, en informatique, en programmation, et peut-être plus particulièrment en C, je conseillerai à tout débutant motivé de ne pas s’attendre à rencontrer des monuments de pédagogie, et il est bon de s’y faire, mieux vaut tôt que tard.

Si vous ne souhaitez pas investir dans un livre, vous pouvez tout à fait vous réserver le loisir de flâner de site en site, sur le Web, apprenant un peu par-ci, un peu par-là. Vous aurez sans doute besoin d’un cours de base, toutefois. Dans un format traditionnel, académique, on trouve par exemple l’introduction au C de Bernard Cassagne, disponible gratuitement en ligne. C’est là encore un texte que je n’ai que parcouru (à croire que tous ceux que j’ai pu lire en entier et qui m’ont effectivement permis de débuter ne m’ont pas tout à fait convaincu !), mais qui me semble, encore une fois, honnête dans son contenu.

Si toutefois c’est là également votre première expérience avec la programmation en général, et selon votre âge et votre formation, un cours de vulgarisation tel que celui du cours de C du Site du Zéro (également disponible en version papier, moyennant une somme raisonnable), écrit par M@teo21, au style bon enfant et simple à comprendre, pourrait davantage vous convenir. J’en connais l’auteur, et j’ai activement aidé à la relecture de ses chapitres. Si désaccords il y a certainement eu, et erreurs et omissions volontaires sont présentes, j’en connais les raisons — que je les trouve justifiées ou non. Somme toute, c’est une base convenable pour un novice absolu, mais attendez vous à enchaîner sur un autre cours de C après cette introduction.

Enfin, pour référence, je citerais le cours de C/C++ de Christian Casteyde, pour sa partie C, cours avec lequel j’ai moi-même débuté. Avec le recul, je ne cautionne pas tout ce qui y est dit (de même que je ne prétends pas défendre le point de vue d’aucun ouvrage particulier que je cite), et la partie C++, en particulier, est d’un goût douteux. Au final, après quelques mois ou quelques années, avec quoi vous avez commencé ne vous paraîtra probablement plus si important, et ce n’est certainement pas cela qui conditionnera votre futur en tant que programmeur. Profitez en donc pour faire des erreurs de parcours ! Vous débutez ; le temps vous pardonnera.

Dans le cadre d’une formation universitaire ou équivalente

À ma connaissance, la plupart (toutes ?) les formations d’informaticien en France comportent des cours de C (et je conçois difficilement un cursus sérieux qui n’en parlerait pas du tout). La portée et la qualité de ceux-ci peut, toutefois, varier grandement.

Typiquement, un cours de C universitaire ne s’attache que rarement au détail et va à l’essentiel, quitte à faire passer des idées imprécises ou incorrectes. C’est bien sûr à vous d’en juger, et le cas échéant, d’opter pour un parcours parallèle autodidacte.

Une autre différence avec l’apprentissage autodidacte pur est la présence du personnel d’enseignement. C’est à la fois un plus considérable, pouvant vous apporter une aide et un complément d’information sous la forme d’un point de vue humain et d’une expérience concrète que vous pouvez interroger, et un biais non négligeable. Le formateur vous forme à son image, selon ses habitudes, ses pratiques. Et, soyons réalistes, disons simplement que cela peut être un avantage comme cela peut très bien ne pas l’être…

Au-delà du C

Tout le monde vous le dira, le langage n’est qu’un langage, un outil de communication entre la machine et vous. Il ne faut pas cependant en sous-estimer l’importance, car, de la même façon que vos pensées se traduisent naturellement en mots dans votre langue maternelle, il y aura des concepts et des techniques de programmation qui vous paraîtront plus ou moins intuitifs, selon la langue que parlent vos doigts sur le clavier.

Mais si le C n’est qu’un intermédiaire, que faut-il d’autre pour programmer ? Et bien si le langage détermine la forme, dans le fond, la programmation est avant tout un savant mélange d’algorithmique et de génie logiciel. Autrement dit, à supposer que vous avez en tête une idée de ce que vous voulez réaliser, il vous faudra encore réfléchir à comment le faire. Et fort heureusement, il y a des techniques et des méthodes pour cela. L’algorithmique s’attaque davantage à des questions de fond (l’équivalent de « comment je fabrique un pneu », si vous fabriquiez une voiture), le génie logiciel s’occupe des questions d’organisation (« faut-il monter les pneus avant les roues ? »).

Je pense, pour ma part, qu’il est essentiel d’acquérir des notions d’algorithmique tôt dans son cursus (soit pendant l’apprentissage du langage, soit juste après en avoir acquis les bases). D’autre part, c’est là une bonne occasion de pratiquer le C sur des problèmes bien définis et bien délimités.

Pour vous initier en douceur, je ne peux que vous conseiller le tutoriel d’algorithmique pour l'apprenti programmeur, effort collaboratif de gasche/bluestorm, qui co-écrit ce blog, Cygal et lasts.

Une fois ces bases bien acquises (ou si l’option précédente ne vous convient pas, pour une raison ou pour une autre), rien ne vaut un bon livre pour approfondir vos connaissances. Un titre très communément cité est le « Cormen et al. », dont le titre formel est Introduction to Algorithms, écrit par Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, et Clifford Stein. Pour l’avoir lu, cette fois-ci, je peux dire qu’il m’a beaucoup aidé.

Quant à la conception logicielle, vous ne trouverez (hélas ?) pas de recommandation de ma part sur le sujet. Je pense qu’il est contre-productif pour un novice de s’attaquer directement à cette science. En effet, celle-ci discute essentiellement de pratiques visant à améliorer la qualité du code de « gros » programmes. Il ne faut pas vous leurrer, cependant, lorsque vous débutez, d’autres difficultés vous attendent, et il serait prémature, à mon avis, de vouloir appliquer des techniques savamment développées et rigidement codifiées à vos premières créations. Vous apprendrez davantage en explorant, en faisant des erreurs, et en tirant des conclusions de la lecture du code d’autres programmeurs plus expérimentés (ou de leurs conseils pour améliorer le vôtre).

Le moment venu, j’ose espérer que vous sentirez de vous-mêmes le besoin de vous offrir les services de nouveaux outils et de consolider vos habitudes par des idiomes et des méthodes.

Résumé : quelques parcours possibles

Débutants programmeurs motivés, version en ligne librement accessible
Débutants programmeurs (très) motivés, version papier
  • The C Programming Language, de Kernighan et Ritchie ;
  • Introduction to Algorithms, de Cormen et al. ;
  • Si aucune expérience préalable de la programmation (savez-vous ce qu’est un compilateur ?), rajoutez un passage par le tutoriel du Site du Zéro, juste la première partie, pour mettre en place votre environnement de travail.
Débutants programmeurs occasionnels
  • Apprenez à programmer en C !, de M@teo21 (ou la version papier) ;
  • En complément ou dans un second temps, selon les objectifs, Algorithmique pour l'apprenti programmeur, de bluestorm et ses amis ;
  • Après le cours de M@teo21, lisez Introduction au langage C, de Cassagne, ou The C Programming Language, de Kernighan et Ritchie, selon vos moyens, pour consolider vos bases de C et en apprendre davantage ;
  • De même, après le cours de bluestorm et Cie, passez à Introduction to Algorithms, de Cormen et al., si vous le désirez.

Si cela vous intéresse, je vous invite également à jeter un coup d’œil à quelques témoignages sur l’expérience autodidacte, que j’ai recueillis. Ceux-ci présentent, je l’espère, un point de vue moins technique et plus humain du processus.

Implémentations du langage C

Écrire du code, c’est une chose, le faire fonctionner sur une machine en est une autre. L’intermédiaire entre le programme écrit en C et le système sur lequel celui-ci est destiné à être exécuté s’appelle généralement une implémentation.

Si dans la théorie, il est tout à fait possible d’imaginer des implémentations fantasques, telle qu’une machine qui exécuterait directement du code C depuis la mémoire, dans la pratique, une implémentation est, le plus souvent, un assemblage des éléments suivants :

Le nombre d’implémentations du langage C est important, pour dire le moindre. Selon le matériel et le système visés, les alternatives diffèrent.

Les sous-sections suivantes ont pour but de vous donner un bref aperçu du paysage. Je me restreins ici aux implémentations destinées aux machines compatibles Intel, aussi connues sous le nom de code « x86 », ainsi que « x86-64 » pour la version 64 bits. Ce sont celles que je connais le mieux et que j’utilise régulièrement. Je tiens toutefois à signaler qu’une bonne partie des solutions citées ici existent également pour d’autres architectures.

Ces listes n’ont en aucun cas la prétention d’être exhaustives ; en fait, elles sont mêmes totalement arbitraires. :)

Quelques compilateurs communs

Résumé : matrice de compilateurs

  Unix Windows C99 Optimisation Gratuit Libre
GCC oui MinGW OK honorable oui oui
MSVC non oui non honorable version Express non
ICC Linux, OS X oui OK très honorable pour Linux non
Clang oui oui OK honorable oui oui
PCC BSD, Linux, autres ? non début minimale oui oui

Et les bibliothèques C ?

La question des bibliothèques C est, à mon avis, moins tranchée que celle des compilateurs : il est plus difficile d’en donner une classification satisfaisante. La bibliothèque C dépend essentiellement du système d’exploitation, et est, de ce fait, le plus souvent entièrement ou en grande partie fournie avec celui-ci. Je passe ici en revue quelques systèmes que je connais plus ou moins bien, et quelques combinaisons de bibliothèques C disponibles pour ceux-ci.

Enfin, une petite remarque qui peut s’avérer utile, certains en-têtes prescrits par la norme, notamment stdarg.h, sont difficilement réalisables sans une connaissance intime des mécanismes du compilateur et des conventions d’implémentation. Pour ces raisons, ils sont le plus souvent le fruit d’une collaboration plus ou moins étroite entre le compilateur et la bibliothèque C, et il serait sot de les classifier strictement dans l’un ou l’autre de ces composants.

De plus, le compilateur empiète souvent sur le domaine de la bibliothèque C, vis à vis de certaines fonctions standards, et se permet de remplacer les appels à celles-ci par des morceaux de code équivalents.

Panoplie du petit programmeur C

Boîte à outils

À un point ou un autre de mon parcours, je me suis aperçu que jouer avec juste mon éditeur et mon compilateur, c’était rigolo, mais pas très productif. Certes, sans une implémentation du langage, on ne fait rien, mais il y a beaucoup d’autres tâches rattachées à la programmation qui peuvent bénéficier d’outils spécifiques.

De quels genre d’outils un programmeur peut-il donc avoir besoin ? Voici ma petite liste personnelle :

Résumé : kits prêts à l’emploi

Pour les grands indécis, voici quelques kits d’outils que vous pouvez essayer ensemble sans trop vous poser de questions :

Programmeur Linux ou Unix
  • Compilateur : GCC, avec Clang ou ICC sous la main pour tester vos programmes avec une implémentation alternative ;
  • Éditeur : Emacs, Vim, ou un éditeur plus simple à prendre en main, si vous préférez (GEdit et Kate viennent à l’esprit) ;
  • Gestion de versions : Git ou Mercurial ;
  • Production, test, distribution : make, automake et autoconf, ou autre chose selon vos objectifs de déploiement ;
  • Débogage : GDB, Valgrind (Linux) ;
  • Autre : cscope, etags ou ctags, pour l’exploration sémantique.
Programmeur Windows
  • Compilateur : Visual C++ ;
  • Éditeur : Visual C++ (même si, personnellement, j’utiliserais Emacs en tant qu’éditeur alternatif) ;
  • Gestion de versions : Git (pas franchement top, sous Windows), Mercurial, ou Subversion (bonne prise en charge sous Windows) ;
  • Production, test, distribution : Visual C++ ;
  • Débogage : Visual C++ ;
  • Autre : Visual C++ pour l’édition et l’exploration sémantique.
Programmeur Windows alternatif
  • Compilateur : MinGW, via un environnement intégré tel que Code::Blocks ;
  • Éditeur : celui de votre environnement intégré, ou alternativement Emacs, Vim, ou un éditeur plus simple (p.ex. Notepad++, gratuit, ou UltraEdit, payant) ;
  • Gestion de versions : de même qu’au-dessus Git, Mercurial, ou Subversion ;
  • Production, test, distribution : Visual C++ ;
  • Débogage : l’interface de débogage de votre environnement intégré.

Questions existentielles

Cette section se préoccupe uniquement de questions politico-philosophiques liées à la programmation en C. Si vous cherchez une liste de questions techniques fréquemment posées, la FAQ de comp.lang.c est certainement la référence.

Si vous aimeriez me poser une question ou juste discuter autour d’un thé (virtuel), n’hésitez pas à m’écrire un e-mail à nhat.minh.le (le domaine est le même que pour la racine de ce site, c’est-à-dire le nom de domaine sans le sous-domaine).

C89 ou C99 ?

Question récurrente et difficile. Même si j’aimerais bien conseiller C99, il est clair que dans certains cas, ce n’est pas vraiment une option (voyez les discussions dans les sections précédentes concernant les versions du langage et les différentes implémentations).

Il est vrai aussi que certaines fonctionnalités de C99 sont plus accessibles que d’autres. Par exemple, inline ou restrict peuvent être remplacés par des macros neutres en mode de compatibilité C89. De même, un usage simple de bool, false et true peut facilement être émulé par un enum et un typedef.

En revanche, les littéraux composés, par exemple, introduisent une nouvelle syntaxe qu’il sera difficile de faire comprendre à un vieux compilateur, de même pour les initialisations nommées, ou les macros à nombre d’arguments variable, pour ne citer que quelques améliorations populaires.

Au final, c’est à vous de décider, en fonction de votre public. Si vous souhaitez rester compatible avec MSVC, il faudra faire des sacrifices ; à l’opposé, si vous utilisez déjà des bibliothèques propres au monde Unix grand public, dans lequel C99 est plutôt bien pris en charge, il n’y a pas vraiment de raison de vous priver. Dans le doute, toutefois, C89 demeure, aujourd’hui encore, le choix sûr.

Pourquoi faire du C quand on peut faire du C++ ?

Parce que c’est du C et pas du C++ ! Plus sérieusement, le choix est vôtre, d’opter pour le C ou le C++. Du point de vue des fonctionnalités, il est clair que C++ offre davantage de possibilités, au détriment de la simplicité.

Le C est un petit langage, selon les standards d’aujourd’hui, dont on peut faire le tour raisonnablement vite (en moins de cinq ans, je dirais). Par rapport au C++, c’est un langage relativement sans surprise, et c’est une qualité que j’apprécie beaucoup, d’un point de vue esthétique, mais surtout pragmatique.

Apprenez les deux, et faites votre choix selon la tâche, les contraintes, et les affinités !

Le C va-t-il disparaître bientôt ; et vaut-il le coup d’être appris ?

De temps à autre, on peut voir resurgir le bon vieux troll selon lequel le C est dépassé et mourant. Comme dans tous les trolls, il y a du vrai et du faux à cela.

De ce que j’ai cru apercevoir, d’une part, il est vrai que le C est à la fois moins enseigné, et utilisé par les jeunes programmeurs. D’autre part, certains secteurs sont dominés par d’autres langages. Le développement d’applications de support d’entreprises emploie, de nos jours, principalement des plateformes de plus haut niveau telles que Java, avec des cycles de développement réduits et un niveau de compétence à l’entrée moindre. De manière analogue, le monde du jeu vidéo est dominé par C++.

La programmation système demeure, toutefois, le territoire privilégié du C. La plupart des systèmes d’exploitation actuels sont construits autour de composants écrits en C, et si successeur il doit y avoir, il est tout sauf décidé, à l’heure où j’écris !

Quel style d’indentation utiliser ?

Le One True Bracing Style bien sûr ! Plus sérieusement, adoptez des conventions qui correspondent à votre sens esthétique, sans vous inventer des règles complètement fantaisistes. Il y a quelques grandes familles et ce n’est probablement pas une mauvaise idée de vous aligner sur l’une d’elles.

Pour ma part, j’ai adopté le KNF NetBSD il y a de cela quelques années, pour des raisons pratiques et aussi tout simplement parce qu’il était parmi les plus proches de mon style personnel de l’époque. Adhérer à un jeu de règles bien codifié et raisonnablement répandu est, à mon avis, généralement une sage décision, pour des questions d’uniformité : s’il est clair qu’il existe plusieurs courants divergents en ce qui concerne l’écriture du C, tous les programmeurs un tant soit peu expérimentés sont plus ou moins familiers avec les principaux styles en usage.

Le goto, c’est mal ?

En un mot : non (si vous savez ce que vous faites). J’ai écrit un billet entier sur le sujet du goto et je vous invite à le lire pour une opinion complète sur la question.

Le préprocesseur, c’est mal ?

Le préprocesseur comme le goto a beaucoup de détracteurs. Il n’en reste pas moins qu’en C, c’est la seule manière d’opérer au moment de la compilation, sans passer par des outils externes. En C++, par exemple, les templates remplissent ce rôle (et plus encore).