Programmation C/Introduction
Historique.
Naissance.
Le langage C a été inventé aux Bells Labs en 1972 par pour permettre l'écriture du , alors développé par Ken Thompson et Dennis Ritchie.
Le système d'exploitation UNIX, né à la fin des années 1960 - début des années 1970, a été écrit directement en langage assembleur pour les machines auxquelles il était destiné. Si le langage assembleur permettait d'écrire un tel système, il n'en était pas moins peu aisé à utiliser. Un tel langage est en effet particulier à un type de processeur, ce qui fait que tout le système devait être réécrit pour le faire fonctionner sur une nouvelle architecture. Cela fait que son principal créateur, Ken Thompson, souhaita rapidement utiliser un langage plus évolué pour réécrire UNIX.
Parmi les langages disponibles à l'époque, (pour "", qui est une simplification de ), créé par Martin Richards en 1966, était intéressant. Sans entrer dans des descriptions détaillées, BCPL est un langage simple, procédural, et non typé. Sa simplicité permettait de créer facilement des compilateurs BCPL sur les machines de l'époque, où les ressources étaient très limitées (le premier ordinateur utilisé par Ken Thompson pour lancer Unix était un PDP-7, qui disposait d'une mémoire de 4000 mots de 18 bits, soit moins de 9 Ko). Ken Thompson l'a fait évoluer pour concevoir le langage B, qu'il a implémenté sur les premières machines UNIX. Cependant, certaines limitations du langage B ont fait qu'UNIX n'a pu être réécrit dans ce langage.
À partir de 1971, Dennis Ritchie fit évoluer B, pour répondre à ces problèmes. À l'image des programmeurs qui incrémentent les versions de leurs programmes, Ritchie « incrémenta » la lettre B pour appeler le nouveau langage C. Cette évolution se « stabilisa » vers 1973, année à partir de laquelle UNIX et les utilitaires systèmes d'UNIX ont été réécrits avec succès en C.
Développement.
Par la suite en 1978, Brian W. Kernighan documenta très activement le langage, pour finalement publier avec Ritchie le livre de référence '. On appelle souvent C K&R le langage tel que spécifié dans la première édition de ce livre.
Dans les années qui suivirent, le langage C fut porté sur de nombreuses autres machines. Ces portages ont souvent été faits, au début, à partir du compilateur "pcc" de Steve Johnson, mais par la suite des compilateurs originaux furent développés indépendamment. Durant ces années, chaque compilateur C fut écrit en suivant les spécifications du K&R, mais certains ajoutaient des "extensions", comme des types de données ou des fonctions supplémentaires, ou interprétaient différemment certaines parties du livre (qui n'était pas forcément très précis). À cause de cela, il fut de moins en moins facile d'écrire des programmes en C qui puissent fonctionner tels quels sur un grand nombre d'architectures.
Normalisation.
Pour résoudre ce problème, et ajouter au C des possibilités dont le besoin se faisait sentir (et déjà existantes dans certains compilateurs), en 1989, l'organisme national de normalisation des USA (ANSI) normalisa le C. Le nom exact de cette norme est ANSI X3.159-1989 "Programming Language C", mais elle fut (et est toujours) connue sous les dénominations "ANSI C" ou "C89". Puis l'ANSI soumit cette norme à l'Organisation internationale de normalisation (ou ISO), qui l'accepta telle quelle et la publia l'année suivante sous le numéro ISO/IEC 9899:1990 (le document étant connu sous le nom "ISO C90", ou "C90"). Le besoin de normalisation de l'époque étant extrêmement pressant, pratiquement tous les éditeurs de compilateurs C de l'époque se sont mis à modifier leurs compilateurs pour supporter la norme (et même n'ont pas attendu la publication officielle pour lancer ces modifications), et de fait la quasi totalité des implémentations existant à ce jour comprennent ces normes. L'ISO publia dans les années qui suivirent deux ensembles de correctifs, et un "amendement" pour la gestion des caractères internationaux.
Étant donnée la grande diversité des implémentations existants au moment de l'élaboration de la norme, et le principe de négociation qui base les processus de normalisation, la norme C est un compromis. Son but était principalement double : d'une part assurer le plus possible la portabilité du code C, pour simplifier le portage de programmes C d'une implémentation à une autre (ce qui était souvent un cauchemar à réaliser), d'autre part donner une certaine liberté aux éditeurs pour proposer des extensions spécifiques. Pour ce faire, la norme a défini des "niveaux de conformité" pour les programmes C et les implémentations, allant du programme "strictement conforme", que toute implémentation doit accepter, et qui fonctionnera exactement de la même manière, aux programmes dépendant d'extensions.
On peut noter que le livre de Kernighan et Ritchie a été republié dans une seconde édition, pour refléter les changements du C89.
Enfin, en 1999, l'organisme ISO proposa une nouvelle version de la norme, qui reprenait quelques bonnes idées du langage C++ (voir plus bas). Il ajouta aussi le type codice_1 d'une taille minimale de 64 bits, les types complexes, l'initialisation des structures avec des champs nommés, parmi les modifications les plus visibles. Le nouveau document, qui au niveau de l'ISO est celui ayant autorité aujourd'hui, est ISO/IEC 9899:1999, connu sous le sigle "C99". Deux ensembles de correctifs à cette version ont été publiés jusqu'à présent. Au sens strict, la dénomination "ISO C" correspond donc actuellement à la norme de 1999 corrigée, mais l'usage est tel qu'il est préférable de toujours préciser de quelle version on parle (89/90 ou 99), et c'est ce qui sera fait dans cet ouvrage lorsque la distinction sera nécessaire. Il est à noter que, si la norme C90 a été largement adoptée par les éditeurs de compilateurs C, très peu implémentent la version C99. En effet, le besoin des utilisateurs s'est fait moins pressant, et l'effort nécessaire pour rendre les compilateurs conformes a rarement été mené à terme.
L'activité du groupe de travail de la norme C est, depuis, portée plus sur la « maintenance » du langage qu'à de véritables « évolutions ». La prochaine version, pour l'instant dénommée officieusement "C1X" et ISO/IEC 9899:201x officiellement, n'est pas encore publiée et ne sera pas étudiée dans ce livre.
La norme C spécifie la syntaxe du langage ainsi qu'une bibliothèque de fonctions simple. Cette bibliothèque est moins fournie que dans d'autres langages, mais cela est dû au domaine d'utilisation très varié de ce langage. En particulier, pour assurer une portabilité maximale du langage entre les implémentations embarquées, les ordinateurs de type PC et les supercalculateurs (par exemple), certaines fonctions n'ont pas été acceptées dans la norme. On peut citer, entre autres, la programmation parallèle, les communications entre processus, la communication réseau ou les interfaces graphiques...
Cela fait qu'en parallèle de cette normalisation du langage C, certaines extensions ont elles aussi été standardisées, voire normalisées. Ainsi, par exemple, des fonctions spécifiques aux systèmes UNIX, sur lesquels ce langage est toujours très populaire, et qui n'ont pas été intégrées dans la norme du langage C, ont servi à définir une partie de la norme .
Dans ce livre, nous étudierons surtout le langage C tel que défini dans les normes ISO citées ci-dessus. La norme C99 n'étant pas implémentée par tous les compilateurs, et beaucoup de programmes existants étant développés en C90, les différences entre les deux normes seront indiquées à chaque fois que nécessaire. Toutefois, nous illustrerons certains chapitres avec des exemples d'extensions courantes qu'un développeur C peut rencontrer, en particulier concernant les fonctions qui ne sont pas fournies par la norme C elle-même. Mais ces exemples d'extensions seront mineurs. D'autres Wikilivres étudient plus en détails de telles extensions, vous pouvez les trouver en regardant les livres listés sur la page .
Norme et documents de référence.
La norme qui définit le langage C est élaborée au niveau international par un groupe de travail ("working group") de l'ISO. Ce groupe de travail fait partie plus précisément du comité technique commun à l'ISO et à la Commission Electrotechnique Internationale, le Joint Technical Commitee 1, qui élabore les normes internationales concernant les technologies de l'information. Il se décompose en sous-comités, donc le SC22, responsable des langages informatiques. Le SC22 rassemble plusieurs groupes de travail, chacun portant sur un langage spécifique, ou sur des considérations indépendantes des langages. On peut ainsi citer, par exemple :
Comme pour toute norme internationale, c'est l'ISO qui décide des modalités de sa distribution. Comme la grande majorité des normes ISO, celle-ci n'est pas en libre distribution, mais en vente. Le lecteur désirant acheter un exemplaire de la norme peut le faire sur le site officiel de l'ISO, par exemple.
Les corrections, ou questions, concernant la norme sont diffusées individuellement par le WG14 sur leur site sous le nom de "Defect Report" (DR), et rassemblées pour publication officielle dans des "rectificatifs techniques" ou "Technical Corrigenda" (TC). Deux ont été publiés pour le C99, en 2001 et 2004.
Par ailleurs, les "brouillons" (ou "drafts") de la norme appartiennent au groupe de travail, qui peut décider de les publier. C'est le cas des documents n869, qui est le dernier brouillon disponible avant la publication de C99, et n1124, correspondant au C99 auquel ont été ajoutés les TC1 et TC2 (le TC3 ayant été publié en 2007).
On pourra noter que, tout comme l'ANSI l'a fait pour le C89, le WG14 a publié un "Rationale", qui est un commentaire de la norme C99. Ces deux textes (en anglais, toujours) peuvent être intéressants pour comprendre les motivations de certains choix dans l'évolution du langage.
Tous ces documents sont disponibles sur le site officiel du groupe de travail (les URLs et références se trouvent dans la bibliographie à la fin de ce livre).
Toutefois, il faut bien noter qu'une norme est un texte très technique, qui sert de référence, et est très loin d'être un texte pédagogique. Un débutant fera mieux de lire un ouvrage comme ce wikilivre pour apprendre le C que lire directement la norme, au risque d'être rapidement découragé. Le présent ouvrage est construit de manière à ne pas avoir à recourir au texte de la norme, et n'y fera référence que rarement, mais le lecteur intéressé et averti pourra y vérifier des points complexes qui ne seront pas détaillés ici.
C et C++.
Ce livre ne porte pas sur le C++, mais ces deux langages étant d'apparence très proches, il convient, pour éviter la confusion au lecteur désireux d'apprendre l'un ou l'autre, de préciser qu'ils sont très différents et que, si la connaissance de l'un peut aider à l'apprentissage de l'autre, "ils ne doivent pas être confondus". L'idée du langage qui est devenu C++ a été lancée par Bjarne Stroustrup en 1979, dans un souci de faire évoluer le C de manière à le rendre plus « robuste ». L'apport le plus visible de cette évolution est que le C++ est orienté objet, alors que le C est procédural, mais ce n'est pas le seul.
Le langage C++ s'est créé "à partir" du C puis, rapidement, "en parallèle" à lui, et en 1998 est devenu une norme ISO au même titre que le C. Les groupes de travail respectifs du C et du C++ communiquent régulièrement dans le but d'assurer une certaine compatibilité entre les deux langages. De fait, un certain nombre d'idées issues des réflexions autour du C++ se sont vues intégrées dans la norme C99. Cependant, la croyance populaire selon laquelle le C est un sous-ensemble du C++, ou qu'utiliser un compilateur C++ pour un programme C ne pose pas de problème, est fausse, et à plus d'un titre :
Durant l'apprentissage du C, le lecteur devra donc faire attention. Un certain nombre d'éditeurs, mettant à profit la grande proximité des deux langages, distribuent ensemble un compilateur C et un compilateur C++, en appelant parfois l'ensemble "C/C++", ce qui entraîne une grande confusion chez les utilisateurs, qui ont parfois du mal à savoir quel est le langage dans lequel ils travaillent. L'utilisateur doit donc apprendre comment fonctionne son implémentation, pour déterminer quel(s) langage(s), norme(s) et extension(s) elle supporte, et comment le faire fonctionner dans l'un ou l'autre mode.
Une liste de compilateurs, avec les supports des normes, est référencée en Bibliographie.
Pourquoi apprendre le langage C ?
Avec son approche bas-niveau, le C permet d'obtenir des programmes très optimisés, pratiquement autant que s'ils avaient été écrits directement en assembleur. Avec un peu d'effort, il est même possible d'utiliser une approche orientée objet, au prix d'une certaine rigueur que le langage et les compilateurs, dans une certaine mesure, sont très loin d'imposer.
Les systèmes d'exploitation pour ordinateur de bureau les plus répandus actuellement sont Windows de Microsoft, Mac OS X d'Apple, et GNU/Linux. Ils sont tous trois écrits en langage C. Pourquoi ? Parce que les systèmes d'exploitation tournent directement au dessus du matériel de la machine. Il n'y a pas de couche plus basse pour gérer leurs requêtes. À l'origine, les systèmes d'exploitation étaient écrits en assembleur, ce qui les rendait rapides et performants. Toutefois, écrire un OS en assembleur est une tâche pénible et cela produit du code qui ne peut s'exécuter que sur une seule architecture processeur, comme l'Intel X86 ou l'AMD 64. Écrire un OS dans un langage de plus haut niveau, comme le langage C, permet au programmeur de porter son système d'exploitation sur une autre architecture sans avoir à tout réécrire.
Mais pourquoi utiliser le C et non Java, Basic ou Perl ? Principalement à cause de la gestion de la mémoire. À la différence de la plupart des autres langages de programmation, le langage C permet au programmeur de gérer la mémoire de la manière qu'il aurait choisie s'il avait utilisé l'assembleur. Les langages comme le Java et le Perl permettent au programmeur de ne pas avoir à se soucier de l'allocation de la mémoire et des pointeurs. C'est en général un point positif, car il est assez pénible et inutile de devoir se soucier de la gestion de la mémoire lorsqu'on écrit un programme de haut niveau comme un rapport sur les résultats trimestriels.
Cependant lorsqu'on parle d'écrire un programme de bas niveau comme la partie du système d'exploitation qui s'occupe d'envoyer la chaîne d'octets correspondant à notre rapport trimestriel depuis la mémoire de l'ordinateur vers le "buffer" de la carte réseau afin de l'envoyer vers une imprimante réseau, avoir un accès direct à la mémoire est fondamental — ce qui est impossible à faire dans un langage comme Java par exemple. Les compilateurs C produisent de plus très souvent un code rapide et performant.
Est-ce vraiment si merveilleux que le langage C soit un langage si répandu ? Par effet domino, la génération suivante de programmes suit la tendance de ses ancêtres. Les systèmes d'exploitation écrits en C ont toujours des librairies écrites en C. Ces bibliothèques système sont à leur tour utilisées pour écrire des bibliothèques de plus haut niveau (comme OpenGL ou GTK) et le programmeur de ces bibliothèques décide souvent d'utiliser le même langage que celui utilisé par ces bibliothèques système. Les développeurs d'applications utilisent ces bibliothèques de haut niveau pour écrire des traitements de texte, des jeux, les lecteurs multimédia, etc... La plupart d'entre eux choisiront d'utiliser pour leur programme le même langage que les bibliothèques de haut niveau. Et le schéma se reproduit à l'infini...