Comme ça, vous voulez (apprendre à) programmer en C...
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
- Introduction au langage C, de Cassagne ;
- Algorithmique pour l'apprenti programmeur, de bluestorm et ses amis ;
- Ajoutez dans un second temps Introduction to Algorithms, de Cormen et al. pour compléter, si vous pouvez.
- 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 :
- Un compilateur, qui transforme le code en quelque chose de
compréhensible nativement par la machine. Selon les usages, il peut
être intéressant de distinguer dans le compilateur plusieurs
composants :
- le préprocesseur, responsable du langage de macros et d’inclusion ;
- l’éditeur de liens, qui rassemble plusieurs modules (plusieurs fichiers source, des bibliothèques de fonctions pré-écrites, etc.) compilés indépendamment en un seul programme final ;
- et le reste, le compilateur à proprement parler, qui ne porte pas de nom distinctif et qui effectue la transformation même du texte au format natif (souvent dit « objet »).
Un jeu de fonctions fournies par le système, que l’on regroupe typiquement sous la dénomination bibliothèque C. Les normes du langage imposent la présence de certaines définitions dans la bibliothèque C, mais on y retrouve couramment beaucoup d’autres fonctionnalités. Notamment, si le C est le langage de base du système visé, sa langue naturelle dirons-nous, la bibliothèque C contient également des interfaces (API) pour dialoguer avec celui-ci. Sur certaines plateformes (p.ex. Microsoft Windows), il est d’usage de distinguer la bibliothèque de programmation système des routines propres au langage C. Du point de vue du programmeur C, cependant, ce genre de critère importe, à mon avis, assez peu en pratique. À noter aussi que même sous Unix, où il est courant de confondre les interfaces système avec les fonctions utilitaires de la bibliothèque C, il n’est pas rare que ces fonctionnalités soient, en fait, fournies par des composants distincts, développés par des personnes différentes, etc.
Et enfin un jeu de conventions d’implémentation (ABI) qui régissent l’interaction entre les différentes partie d’un même programme, ou entre le programme et ses bibliothèques. Une telle convention peut par exemple répondre à la question : « Dans quel ordre une fonction attend-elle ses arguments ? » Ces règles permettent à différents compilateurs de coexister entre eux, ou avec des bibliothèques développées séparément, voire de faire le pont avec d’autres langages de programmation.
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
GCC (GNU Compiler Collection), que l’on ne présente plus, le compilateur du projet GNU, que l’on ne présente plus non plus. Prend en charge toutes sortes de combinaisons d’architectures et de systèmes possibles et imaginables. Windows, Linux, Unix, quel que soit votre préférence, il y a de fortes chances pour que vous trouviez une version de GCC ou une autre pour satisfaire vos pulsions de C les plus folles. Libre, évidemment.
Sous les systèmes à base de GNU, de BSD, ou d’autres unixoïdes, c’est souvent le compilateur de choix. Sous Windows, c’est une alternative, viable ou pas, à voir selon le projet.
Du point de vue du langage, le dialecte nativement reconnu, le GNU C, apporte bon nombre d’extensions au langage de base. Question respect de la norme, GCC intègre la plupart des fonctionnalités utiles de C99. La prise en charge n’est pas parfaite, mais si vous vous limitez aux constructions bien reconnues, vous ne devriez pas avoir de problèmes.
Du côté de l’optimisation, mon expérience personnelle semble indiquer que GCC est plutôt malin vis à vis des optimisations de haut niveau (qui ont rapport avec la représentation abstraites du langage), et s’en sort honorablement à plus bas niveau, sur x86. Dans l’ensemble, je dirais que les performances sont en générales bonnes.
MSVC (Microsoft Visual C++), le compilateur de Microsoft. Là encore, est-il besoin de le présenter ? Disponible en plusieurs versions, gratuites ou payantes, pour Windows ou Windows, naturellement. C’est le compilateur C pour Windows. Du fait de son statut, les formats et conventions adoptées par MSVC sont plus ou moins des standards de facto sous Windows, que GCC pour Windows (plus précisément, MinGW) ne respecte pas, cependant, ce qui peut poser de sérieux problèmes.
Au niveau du langage, on trouve quelques rares bribes de C99, mais c’est principalement du C89, avec une poignée d’extensions spécifiques à Microsoft. En clair, si vous voulez faire du C99, ce n’est pas une option, sauf si bien sûr, par chance, vous n’avez besoin que des fonctionnalités justement implémentées.
Côté optimisation, il me semble qu’aujourd’hui, c’est plutôt bon, au même niveau, voire mieux, que GCC. Mais je ne m’avancerai pas trop sur ce sujet, je n’ai pas utilisé le compilateur depuis bien cinq ans au moins… Dans tous les cas, comme pour GCC, vous pouvez vous attendre à des performances tout à fait honnêtes.
ICC (Intel C++ Compiler), le compilateur d’Intel. Disponible uniquement pour Linux (gratuitement, à de fins non lucratives), Windows, et OS X, et, comme on peut s’y attendre, que pour les processeurs compatibles Intel, c’est un compilateur tourné vers la performance, et, de mon expérience personnelle, elle est plutôt très bonne, meilleure en générale que celle de GCC ou de MSVC.
Mes brèves excursions dans le code généré par ICC semblent pointer du doigt les optimisations de bas niveau : ICC sait tirer le meilleur de la bête qui sommeille dans votre PC. En particulier, comparé à GCC, la vectorisation et l’optimisation inter-procédurale et inter-modulaire sont d’un tout autre niveau.
Sous GNU/Linux, ICC est compatible avec les conventions de GCC. Sous Windows, il l’est avec celles de MSVC. Outre la performance, vous pouvez vouloir utiliser pour sa prise en charge de C99, qui manque à MSVC. Celle-ci est sans doute au même niveau que pour GCC, c’est-à-dire tout à fait utilisable, en pratique.
Clang, le compilateur d’Apple… ah pardon, je voulais dire, le compilateur basé sur LLVM, sous license BSD, dont le but plus ou moins avoué est de détrôner GCC en tant que compilateur numéro un pour unixoïdes. Développement rapide, enthousiasme communautaire, et performances tout à fait correctes, c’est peut-être le futur de la compilation pour votre système libre ou moins libre préféré.
Question langage, le C99 est, ici encore, plutôt bien géré. Comme pour GCC, c’est très utilisable.
Au niveau du code généré, LLVM est une plateforme de compilation optimisante, et Clang bénéficie directement de ses bienfaits. La qualité du code généré est tout à fait honorable ; les benchmarks actuels semblent placer Clang généralement un peu au-dessous de GCC, parfois un peu au-dessus ; mon avis sur la question est que, franchement, ça se vaut, et vous n’en avez probablement rien à faire, la plupart du temps.
PCC (Portable C Compiler), un des compilateurs historiques d’Unix, remis au goût du jour. Particulièrement populaire parmi les amateurs de systèmes BSD. Disponible pour BSD, Linux, et peut-être d’autres systèmes. Pas franchement stable encore, mais arrive à compiler d’assez larges volumes de codes et de « vrais » programmes correctement.
Côté norme et langage, le but affiché est, comme pour GCC et Clang, une prise en charge totale de C99. Pour l’instant, une bonne partie de celui-ci est reconnu, mais il reste du travail à faire, autant pour consolider fonctionnalités existantes que rajouter celles qui manquent.
Quelques optimisations classiques ainsi qu’une structure de base sont en place, mais on est, ici aussi, loin de GCC ou Clang.
Dans l’ensemble, PCC est surtout un compilateur que vous pourriez vouloir essayer, ne serait-ce que pour tester la correction de vos programmes sur des implémentations plus ou moins modestes, sans tomber dans le compilateur-gadget ou l’épave abandonnée depuis quinze ans.
Enfin, deux logiciels un peu particuliers : MCPP et Comeau C/C++.
MCPP est un préprocesseur seul, développé pour être strictement conforme à la norme et fournir des diagnostics détaillés d’erreur et d’avertissement liés aux macros et aux inclusions. Si vous faites de la méta-programmation complexe avec le préprocesseur, c’est probablement une bonne idée de vérifier que votre code passe sous MCPP.
Comeau C/C++ est, quant à lui, un compilateur C-à-C, c’est-à-dire qu’il produit du C en sortie (un peu comme le premier compilateur C++, Cfront). Son principal avantage est le respect des normes. Je ne l’ai jamais utilisé (payant…), mais j’aime bien le principe, alors je le liste ici. :)
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.
Si vous développez pour GNU/Linux, comme pour beaucoup d’autres choses, il y a le choix. La bibliothèque C standard est la glibc, sans surprise, développée par le projet GNU. De ce que j’ai pu voir du code, c’est assez tentaculaire ; on trouve par exemple ici et là du code assembleur spécialisé pour une poignée d’architectures. Je m’abstiendrai de juger, je constate simplement : le but n’était certainement pas de faire une bibliothèque poids plume.
Question normes, la glibc prend en charge une bonne partie de C99, et incorpore beaucoup d’interfaces POSIX.
D’autres bibliothèques C existent, notamment pour les systèmes embarqués : uClibc, dietlibc, EGLIBC, etc. Je ne les connais pas très bien.
Pour les systèmes BSD en général, et plus particulièrement NetBSD, mon système d’exploitation de prédilection actuel, la bibliothèque C est développée côté système, c’est-à-dire par le projet BSD concerné, plutôt que côté compilateur (le compilateur dominant utilisé pour les projets BSD est actuellement GCC).
De mon expérience, le code est typiquement plus léger que celui de la glibc, plus simple. Cela peut être un avantage comme un désavantage, encore une fois, à vous de juger. Personnellement, et de manière complètement arbitraire, la simplicité me plait tant qu’elle ne nuit pas de manière inconsidérée à la performance, et il me semble que dans la pratique, la bibliothèque C BSD s’en sort plutôt bien. Mais ce n’est que mon humble avis.
Le niveau de prise en charge de C99 est variable, mais du moins la volonté est là et ce qui est présent est tout à fait utilisable (à voir selon vos besoins spécifiques). POSIX est, quant à elle, comme pour la glibc, bien respectée.
Sous Windows, l’histoire est un peu différente. Les fonctions mandatées par la norme C sont isolées du reste des interfaces système (la fameuse Windows API).
Microsoft fournit avec MSVC la C Runtime Library, pour les fonctions de base du C ; la règle générale est que chaque compilateur dispose de sa propre bibliothèque. L’implémentation des fonctions et interfaces système est, dans mon souvenir, partagée, avec éventuellement des couches de glue pour faire tenir le tout (souvenez vous, sous Windows, chaque compilateur possède plus ou moins ses propres formats et conventions). Ici, selon les versions, vous pouvez vous attendre à trouver plus ou moins de morceaux de C99 ; pour POSIX, il faudra voir ailleurs (et généralement pas voir du tout).
J’aimerais également mentionner ici Dinkumware, une implémentation commerciale des bibliothèques C, prenant en charge la totalité de C99, et disponible sur plusieurs systèmes et architectures (en particulier Windows, Linux, et certains Unix non identifiés sur leur site Web).
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 :
Un bon éditeur de code. L’éditeur est votre ami, l’éditeur est votre seul allié à travers vos longues heures de codage. N’oubliez pas (même à l’agonie !). Non pas que vous ayez tant à écrire, il s’agit avant tout d’y être confortable. Le confort se définit différemment selon les personnes. Question d’interface utilisateur ; il y en a pour tous les goûts (ou presque) ! Il y a ceux qui peuvent se commander entièrement au clavier ; il y a ceux qui utilisent intensivement la souris. Il y en a des plus ou moins épurés, plus ou moins jolis (très subjectif). Au final, c’est à vous de choisir.
J’utilise Emacs, entièrement au clavier ; j’y suis efficace, et il m’est plus confortable de garder mes mains essentiellement posées sur le clavier. Si vous optez pour une solution similaire, c’est-à-dire pilotée au clavier, je vous recommande vivement, si ce n’est déjà fait, de reprogrammer la disposition des touches de votre clavier afin de ne pas épuiser inutilement vos doigts.
Un logiciel de gestion de versions, c’est-à-dire un programme permettant de stocker, restaurer, comparer et fusionner plusieurs versions d’un même code, étalées dans le temps (historique) ou l’espace (travail collaboratif). J’utilise Git ; c’est un bon outil, quelque peu difficile à prendre en main, mais efficace, portable, activement utilisé, développé et supporté, libre et gratuit. Tout n’est pas idéal au pays des manchots roses, mais dans l’ensemble, je pense que c’est un bon compromis. S’il ne vous plait pas, peut-être préférerez-vous Mercurial, au concept similaire, ou Subversion, qui fonctionne sur un autre modèle.
Un environnement de production, test et distribution. Un projet de taille raisonnable se compose rarement uniquement de fichiers C à compiler et lier ensemble. Les sources doivent le plus souvent être traitées dans un ordre précis, une partie de ce code C doit peut-être être générée automatiquement, etc. En anglais, on parle de build, et des outils spécifiques existent : make (vénérable utilitaire Unix dont il survit plusieurs variantes), CMake, scons, automake, et d’autres encore. Je n’ai pas vraiment trouvé mon bonheur dans ce domaine et me contente le plus souvent de make, pour mes projets personnels.
De même, vous voudrez automatiser les tests (lorsque que cela est faisable), ainsi que la distribution — selon votre public, cela peut aller d’une simple génération automatique de la documentation à la création d’installateurs pour Windows, ou de paquetages binaires pour un Unix de votre choix, en passant par des scripts de configuration. Parfois, cela est intégré à votre outil de build, parfois non. Il existe également des utilitaires spécialisés, par exemple, pour l’écriture de tests (p.ex. ATF), ou celle des scripts de configuration (p.ex. autoconf).
Des outils de débogage. Ce qui vient après l’écriture du code et la compilation ? Le débogage, assurément ! À moins que vous ne passiez le reste de votre vie à écrire des hello world, vous ferez des erreurs. Et s’occuper de ces erreurs est une tâche hautement fastidieuse, source d’une grande part de la frustration du programmeur. Fort heureusement, il existe des outils pour nous aider dans cette épreuve.
Les plus connus sont les débogueurs source, qui permettent d’examiner l’état d’un programme durant son exécution par rapport au code à partir duquel il a été compilé. On peut citer dans cette catégorie GDB, le débogueur du projet GNU, le plus souvent utilisé en conjonction avec GCC (mais ce n’est pas du tout une obligation) ; sous Windows, j’utilisais celui de Visual C++.
Une autre classe importante d’outils de débogage est celle des débogueurs mémoire. L’exemple type en est Valgrind, bel outil, mais uniquement disponible pour GNU/Linux et Mac OS X. Une alternative payante est Purify. Il existe également des solutions plus modestes telles qu’Electric Fence (et ses descendants), ou dmalloc.
Enfin, j’aimerais discuter un peu des aides à l’édition et à l’exploration sémantiques. Je parle ici de l’autocomplétion, de la refactorisation assistée, etc. Où est donc définie telle ou telle fonction ? Quel est son prototype ? Ce sont là des questions liées à ce que j’appelle l’exploration du code. De manière analogue, renommer une structure dans tous vos fichiers source est une action d’édition sémantique. Les environnements de développement intégrés (Visual Studio, Eclipse, etc.) incorporent généralement ce genre de fonctionnalités de manière transparente. Étant donné que je code avec un « simple » éditeur, je n’ai pas accès à ce confort. C’est sans doute une question d’habitude, mais cela ne me manque généralement pas. Pour naviguer dans une hiérarchie importante de fichiers, je m’aide généralement de simples recherches textuelles (avec grep, par exemple) ou, si je suis amené à le faire fréquemment, de cscope et son interface Emacs. Pour de grandes opérations d’édition automatisée, j’utilise des outils de remplacement textuel tel que sed ou la commande Emacs adaptée, selon mes besoins.
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,
inlineourestrictpeuvent être remplacés par des macros neutres en mode de compatibilité C89. De même, un usage simple debool,falseettruepeut facilement être émulé par unenumet untypedef.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
gotoet je vous invite à le lire pour une opinion complète sur la question.- Le préprocesseur, c’est mal ?
Le préprocesseur comme le
gotoa 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).
![[Atom]](feed.png)