Open Library

Retour vers l'index principal.

Le langage C

A-propos

Le C est un ancien langage de programmation dit de bas niveau. Ces deux derniers termes signifient qu'on parle ici d'un langage proche de la machine. Ce qui lui confère un large contrôle sur les ressources matérielles et ce de façon plus significative qu'un langage de haut niveau.

Aussi, le C est un langage compilé. Donc, un logiciel développé en C sera très rapidement exécuté sur la machine pour laquelle il a été conçu. Ceci s'explique car avant l'exécution de ce programme, le code source en C sera compilé dans un langage compréhensible par la/les machine(s) ciblée(s). Ce langage machine, qui est donc compilé, s'exprime au format binaire qui correspond à une suite de 0 ou de 1. Bien que C soit très fréquement compilé, des interpréteurs C peuvent également être trouvés. À savoir qu'un interpréteur va, contrairement à un compilateur, interpréter en temps réel le code-source du programme ; ce qui impacte sur les performances d'exécution qui seront amoindries.

Le C est un langage efficace de par son optimisation, sa structure de formatage simple qu'on peut certainement qualifier de traditionnelle. Ce langage a eu un impact considérable historiquement parlant sur l'évolution des langages de programmation. Il a donc influencé à des degrés plus ou moins larges des langages toujours utilisés actuellement tels que Java, JavaScript, C++ et d'autres. Cependant le C n'est pas une relique ancestrale, c'est bien toujours aujourd'hui un langage vivement utilisé. Le C reste en temps que langage de bas niveau, un des meilleurs de par sa simplicité et de prise en main pour les développeurs. Ce langage reste donc un langage populaire et de choix qui reste bien ancré dans le domaine du développement d'applications demandant de hautes performances sur un minimum de ressources matérielles.

Quelques logiciels notables écrits en langage C

Unix, Doom, Duke Nukem 3D, Linux, OpenBSD, Anarch, dwm, git, Vim, Quake, Wolfenstein 3D et plus.

Le C est généralement considéré comme un langage difficile à apprendre à cause de sa nature dite de bas niveau et due à la grande quantité de contrôle vis-à-vis du matériel, ce qui confère aux développeurs de larges possibilités. Comprendre correctement le fonctionnement d'un ordinateur dans ses couches inférieures est crucial pour le C. Cela empêchera le programmeur de faire planter la machine si son code est mal programmé. Le programmeur dispose d'un contrôle total et donc des responsabilités qu'il en découle. Il est important de prendre en compte des éléments délicats tels que le comportement inattendu de certains opérateurs (+,-,*,/,=) ou la gestion manuelle de la mémoire. C'est ce qui peut dissuader un grand nombre de codeurs modernes de choisir le langage C, mais c'est aussi ce qui rend inévitable d'obtenir de si bonnes performances grâce au compilateur.

D'un autre côté, le C en tant que langage est assez simple sans concepts modernes tels que la programmation orientée objet. Apprendre le langage C n'est pas aussi difficile qu'on pourrait le penser, mais plutôt difficile à maîtriser, tout comme tout autre véritable art. Dans tous les cas, vous devez apprendre le C, même si vous ne prévoyez pas de programmer régulièrement. C'est le langage le plus important de l'histoire et la lingua franca de la programmation. Vous rencontrerez le C dans de nombreux endroits et devrez au moins le comprendre : les programmeurs utilisent très souvent le langage C au lieu du pseudo-code pour expliquer les algorithmes, le C est utilisé pour optimiser les parties critiques même dans les projets non-C, de nombreux langages compilent en C, il est partout et vous devez le comprendre comme vous devez comprendre l'anglais.

Certains des traits typiques du langage C incluent une utilisation abondante du préprocesseur, des pointeurs et de comportement indéfinis. Les instructions préprocesseur sont appelées "macros". Le code sous-jacent en C de ces macros est parsemé de "#ifdef" partout, ce qui modifie le code juste avant que la compilation ait lieu. Ceci est principalement utilisé pour la configuration du temps de compilation et / ou afin de réaliser de meilleures performances et / ou assurer une certaine portabilité. Les pointeurs permettent un accès direct à la mémoire utilisé, par exemple pour l'allocation de mémoire. Celles-ci peuvent faire planter l'application, voir la machine à cause de fuites de mémoire. Les comportements indéfinis sont des choses délibérément laissées en C afin de permettre aux compilateurs de générer du code très efficace; cependant cela conduit parfois à des bogues étranges ou à un programme fonctionnant sur une machine mais pas à un autre. Donc le langage C nécessite une certaine connaissance de ses spécifications. Aussi, il arrive qu'on rencontre des déclarations complexes comme "void (*float(int,void (*n)(int)))(int)", ces déclarations atypiques sont souvent un sujet de blagues.

Contrairement à beaucoup de langages modernes, le C en soi n’offre pas trop de fonctionnalités avancées et sophistiquées telles que l’affichage de graphismes, travailler sur le réseau, l’obtention de l’état brut du clavier, etc. Le langage de base ne possède même pas de concept d’entrée ou de sorties, il s’agit d’un pur processus de valeur en mémoire. La bibliothèque standard offre des fonctionnalités de base comme les E/S (I/O en anglais) avec des flux d’entrées et de sorties standard, la gestion de fichiers sur un disque, la manipulation de chaînes de caractères, la gestion du temps, l’évaluation de fonctions mathématiques et d’autres choses… Mais pour des fonctionnalités plus avancées vous aurez besoin d’une bibliothèque externe comme la SDL ou bien celles définies par Posix.

On dit que le C est semblable à un 'assembleur portable', non seulement parce qu’il est de bas niveau et presque aussi performant que l’assembleur, mais aussi parce que de nombreux langage choisissent de compiler en C plutôt qu’en assembleur. Même si le C est structuré (par exemple : les structures de contrôle comme des branches et des boucles) et peut être utilisé de la même manière qu'un langage de 'haut niveau'. Il est aussi possible d’écrire du code semblable à l’assembleur qui opère directement avec sur des octets en mémoire via les pointeurs sans avoir affaire à des mécanismes de sécurité. C'est pourquoi le C est fréquemment employé pour écrire certains éléments, comme des pilotes matériels. D'un autre côté, il y a ceux qui ont du mal à comparer le langage C au langage assembleur, car les compilateurs C modifient beaucoup de code et ne donnent pas nécessairement ce que vous avez écrit.

Le consensus grand public reconnaît que le C est parmi les meilleurs langages pour écrire du code de bas niveau, ainsi que du code qui requiert de hautes performances, telles que les systèmes d’exploitation, les pilotes ou les jeux-vidéos. Même les bibliothèques scientifiques qui utilisent des interfaces en langue normale, telles que diverses bibliothèques en Python d’apprentissage automatique, ont en général leur cœur critique écrit en C afin d’atteindre des performances élevées. La plupart des gens vous diront que pour les choses en dehors de ce champ d’application, le C n’est pas un bon langage, ce avec quoi ‘nous’ ne sommes pas d’accord ‘nous’ recommandons d’utiliser le C pour pratiquement tout ce qui est supposer persister ; c’est-à-dire que je vais citer l’auteur ici dont la page de référence est en bas de cette même page-ci ¹ ‘si vous voulez écrire un bon site web dynamique, vous devriez probablement l’écrire en C’. Pour ma part, dès que j'ai vu cette phrase, j'ai immédiatement pensé : 'Non!' Pour résumer ma réflexion, je me suis dit que ce serait réinventer la roue. Même si je pense que c'est presque impossible, l'idée en elle-même est certainement réalisable, mais le langage C ne me semble pas approprié pour la création d'un site web dynamique. Je dois admettre que je n'ai personnellement qu'une expérience limitée dans le développement de sites web de ce genre, en utilisant des langages tels que PHP en relation avec une base de données SQL. Cela dit, à titre d'exemple de ma modeste expérience.

Le C n'est PAS un sous-ensemble du C++. Le simple exemple d'un programme C utilisant le mot ‘class’comme nom de variable le prouve : c'est impossible en C++. Les différences entre C et C++ sont parfois plus importantes, notamment en termes de sémantique, et peuvent poser problème à ceux qui ne les connaissent pas. Certes, de nombreux programmes C fonctionnent parfaitement en C++, mais pas tous, et certains programmes C fonctionnant en C++ auront un comportement différent. Il faut toujours en être conscient.

Est-ce que le C est de bas ou de haut niveau ? Ça dépend du contexte. Premièrement en faisant un bond en arrière lorsque tous les ordinateurs étaient programmés en langage assembleur, le C était vu comme un langage de haut niveau, simplement parce qu’il offrait le plus haut niveau d’abstraction en ce temps-là. Aujourd’hui, avec l’avènement de langage comme le Python et le JavaScript, le C est perçu comme un langage de très bas niveau en comparaison. Tout dépend de la façon dont on parle du C ; qu’on le considère comme un ancien ou un langage de programmation moderne; mais aussi des langages auxquels on le compare. Ensuite, ça dépend aussi de votre façon de programmer en C : vous pouvez choisir d’imiter la programmation en assembleur en évitant l’utilisation de bibliothèques, touchez directement au matériel, éviter d’utiliser des fonctionnalités complexes et ainsi créer vos propres abstractions ; ce moment vous faite vraiment de la programmation de bas niveau. D’un autre côté, vous pouvez aussi émuler une approche moderne de développement avec un style de programmation de plus haut niveau en C aussi, vous pouvez même imiter la programmation orientée objet (POO) et faire une sorte de C++ avec une syntaxe différente. Vous pouvez utiliser des bibliothèques qui vous permettent de travailler facilement avec des chaînes de caractères, des macros lourdes qui rendent le langage plus abominable, vous pouvez écrire votre propre ramasse-miettes (gestion de mémoire), etc. Dans ce cas, vous faites essentiellement de la programmation de haut niveau.

Exemple

Écrivons un simple programme appelé ‘divisor tree’ (arbre diviseur). Ce programme lit interactivement les nombres positifs (inférieurs à 1000) fournis par l'utilisateur et, pour chacun d’eux, affiche l’arbre binaire des diviseurs. Ainsi, si un nombre possède des diviseurs, ceux les plus proches les uns des autres seront ses enfants. Si une entrée invalide est fournie, le programme s’arrête. L’arbre sera écrit au format (L N R), où N est le numéro du nœud de l'arbre, L son sous-arbre gauche et R son sous-arbre droit. Ce problème est conçu pour illustrer la plupart des fonctionnalités de base d'un langage de programmation (structures de contrôle, définition de fonctions, récursivité, entrées/sorties, etc.). Considérons maintenant ce programme comme notre programme standardisé pour illustrer les langages de programmation.

Voici le programme écrit en C99 (que cela serve également de référenced 'implémentation du programme) :

#include <stdio.h> // include standard I/O library

// recursive function, prints divisor tree of x
void printDivisorTree(unsigned int x)
{
  int a = -1, b = -1;
 
  for (int i = 2; i <= x / 2; ++i) // find two closest divisors
    if (x % i == 0)
    {
      a = i;
      b = x / i;

      if (b <= a)
        break;
    }

  putchar('(');

  if (a > 1)
  {
    printDivisorTree(a);
    printf(" %d ",x);
    printDivisorTree(b);
  }
  else
    printf("%d",x);

  putchar(')');
}

int main(void)
{
  while (1) // main loop, read numbers from the user
  {
    unsigned int number;
    printf("enter a number: ");

    if (scanf("%u",&number) == 1 && number < 1000)
    {
      printDivisorTree(number);
      putchar('\n');
    }
    else
      break;
  }

  return 0;
}

Exécuter ce programme peut donner quelque chose comme ceci :

enter a number: 32
((((2) 4 (2)) 8 (2)) 32 ((2) 4 (2)))
enter a number: 256
((((2) 4 (2)) 16 ((2) 4 (2))) 256 (((2) 4 (2)) 16 ((2) 4 (2))))
enter a number: 7
(7)
enter a number: 0
(0)
enter a number: 15
((5) 15 (3))
enter a number: quit

Histoire et contexte

Le C a été développé en 1972 par la société Bell Labs parallèlement au système d'exploitation Unix de Dennis Ritchie et Brian Kerninghan ; en tant que successeur du langage B (langage portable récursif) écrit par Dennis Ritchie et Ken Thompson qui s'inspire à son tour du langage ALGOL (blocs de code, portée lexicale… ). Le C a été tout un temps appelé NB de ‘New B’ (Nouveau B). Le C était intimement lié à Unix et à sa culture de hacker, les deux projets continueraient à être développés ensemble en s’influençant mutuellement. En 1973, Unix a été réécrit en C. En 1978 Kerninghan et Ritchie ont publié un livre nommé ‘The C Programming Language’, connu sous le nom de K&R et qui est devenu une sorte de spécification du C. En mars 1987, Richard Stallman accompagné d’autres personnes ont publié la première version du compilateur C GNU. Le compilateur officiel du projet GNU et aussi le compilateur qui allait devenir un des plus largement utilisé. En 1989, le standard ANSI C, aussi connu sous la dénomination C89 a été publié par l’ANSI (American National Standards Institute). Très bien soutenue, il s'agit d'une norme globalement de bonne augure. Cette même norme a également été adoptée un an plus tard par l'ISO, la norme C90 faisant donc référence au même langage. En 1999, l'ISO a publié une nouvelle norme, la C99, qui reste une excellente référence. Plus tard, entre 2011 et 2017, la norme a été révisée pour devenir les normes C11 et C17, mais celles-ci ne sont plus considérées comme satisfaisantes.

Standarisation

Le C n’est pas un langage unique, plusieurs normes ont été élaborées durant des années depuis sa création en 1970. Les normes définissent deux branches principales : le langage de base et la bibliothèque standard. Les normes et les versions les plus notables sont :

Une référence en ligne assez intéressante sur toutes les différentes normes (y compris pour le C++) est disponible à l'adresse : https://en.cppreference.com/w/c/99

Il est conseillé d’utiliser les normes C99 ou encore C89 car les versions les plus récentes sont considérées comme lourdes et n’ont pas un si bon support par les compilateurs, ce qui les rend moins portables et offrent donc aussi moins de liberté.

Les normes C99 et précédentes ont largement fait leurs preuves au fil du temps; leur application contribuera également à assurer la continuité de votre programme. Cela est dû en grande partie au fait que le C a été établi et mieux testé que tout autre langage. C’est l’un des langages les plus ancie, et la majorité des logiciels les plus essentiels sont écrits en C. Le compilateur C est l'une des toutes premières choses qu'une nouvelle plate-forme matérielle doit implémenter. Donc les compilateurs C seront toujours présents, au moins pour des raisons historiques. Le C a aussi été très bien conçu et ce de manière relativement minimaliste, avant l'avènement des fonctionnalités modernes et des foutaises telles que la POO qui paralyse presque tous les langages dit modernes.

Compilateurs

Le langage C est extrêmement bien établi, standardisé et implémenté, ce qui explique le grand nombre de compilateurs C disponibles. Citons quelques-uns des plus remarquables.

Bibliothèque standard

Outre le langage en pur C, la norme C spécifie un ensemble de bibliothèques qui doivent être accompagnées d’une implémentation C conforme à la norme, appelé bibliothèque standard. Cela inclut par exemple la bibliothèque ‘stdio’ qui permet les entrées/sorties standards (lecture ou écriture vers un écran ou des fichiers), ou bien encore la bibliothèque ‘math’ pour des fonctions mathématiques. L’utilisation de ces librairies est généralement acceptable, car elles sont requises par la norme, ce qui limite les risques de dépendance. Cependant de nombreuses implémentations C ne sont pas totalement conformes à la norme et peuvent être fournies sans la bibliothèque standard. Aussi, de nombreuses implémentations ‘stdlib’ sont médiocres et ne permettent pas de garantir des performances optimales (taille ? Vitesse?), etc.

La bibliothèque standard (libc) fait l'objet de vifs débats car, si son interface et son comportement sont définis par la norme C, son implémentation dépend de chaque compilateur. Étant donné sa grande utilisation, il est essentiel de veiller à ce qu'elle soit parfaitement écrite. Cependant, il faut TOUJOURS choisir nos priorités et faire des compromis. Mathématiquement, il est impossible qu'une implémentation ultime soit à la fois extrêmement rapide, extrêmement économe en mémoire, extrêmement portable et extrêmement compacte. Choisir son environnement C implique donc généralement de choisir le compilateur C et l'implémentation de la bibliothèque standard (stdlib). Comme vous l'avez probablement deviné, les implémentations courantes (glibc et autres) sont lourdes et souvent médiocres. Heureusement, de meilleures alternatives existent, telles que :

Avantages et inconvénients

Tout d'abord, résumons quelques-unes des raisons pour lesquelles le C est si bénéfique :

Maintenant admettons que rien n’est parfait, pas même le C ; C’était l’un des premiers langages de niveau relativement élevé et, même s’il s'est avéré extrêmement bien conçu, certains aspects de ce langage n’ont pas été à la hauteur. Nous privilégions toujours le C, que est considéré comme l'un des meilleurs choix, mais il est bon d’en connaître les inconvénients et les petits problèmes, ne serait-ce que pour concevoir un jour un meilleur langage. Gardez à l'esprit que ce ne sont que des suggestions, qui pourront bien sûr faire l'objet de contre-arguments et de discussions ultérieures. Voici donc quelques points négatifs de ce langage :

Retour en haut de page.


Référence: ¹ Drummyfish, Less Retarded Wiki - C, TastyFish, https://www.tastyfish.cz/lrs/c.html (Archive). Dernière visite le 13 septembre 2025.