C (langage) — Wikipédia

Wiki Loves Monuments : photographiez un monument historique, aidez Wikipédia et gagnez !

# C (langage)

Un article de Wikipédia, l'encyclopédie libre.
Pour les articles homonymes, voir C.

C
Apparu en | 1972
Auteur | Dennis Ritchie
Développeur | Dennis Ritchie, Bell Labs
Paradigme | Impératif, procédural, structuré
Typage | Statique, faible
Normes | ANSI X3.159-1989 (ANSI C, C89) ISO/CEI 9899:1990 (C90) ISO/CEI 9899:1999 (C99) ISO/CEI 9899:2011 (C11)
Influencé par | B (CPL, BCPL), ALGOL 60, Lisp
A influencé | awk, csh, C++, C#, Objective-C, D, Concurrent C, Java, JavaScript, PHP, Perl
Implémentations | GCC, MSVC, Borland C, Clang, Watcom C

Le C est un langage de programmation impératif, généraliste, conçu pour la programmation système. Inventé au début des années 1970 pour réécrire UNIX, C est devenu un des langages les plus utilisés. De nombreux langages plus modernes comme C++, Java et PHP reprennent des aspects de C.

## Histoire[ modifier | modifier le code]

Ken Thompson (à gauche) et Dennis Ritchie (à droite).

Le langage C a été inventé au cours de l'année 1972 dans les Laboratoires Bell. Il était développé en même temps que UNIX par Dennis Ritchie et Ken Thompson. Ken Thompson avait développé un prédécesseur de C, le langage B, qui est lui-même inspiré de BCPL. Dennis Ritchie a fait évoluer le langage B dans une nouvelle version suffisamment différente, en ajoutant notamment les types, pour qu'elle soit appelée C[1].

Bien que C soit officiellement inspiré de B et de BCPL, on note une forte influence de PL/I (ou de PL360) ; on a pu dire que C était à Unix et au PDP-11 ce que PL1 fut pour la réécriture de Multics.

Par la suite, Brian Kernighan aida à populariser le langage C. Il procéda aussi à quelques modifications de dernière minute.

En 1978, Kernighan fut le principal auteur du livre The C Programming Language décrivant le langage enfin stabilisé ; Ritchie s'était occupé des appendices et des exemples avec Unix. On appelle aussi ce livre « le K&R », et l'on parle de C traditionnel ou de C K&R lorsqu'on se réfère au langage tel qu'il existait à cette époque.

### Normalisation[ modifier | modifier le code]

En 1983, l'Institut national américain de normalisation (ANSI) a formé un comité de normalisation (X3J11) du langage qui a abouti en 1989 à la norme dite ANSI C ou C89 (formellement ANSI X3.159-1989). En 1990, cette norme a également été adoptée par l'Organisation internationale de normalisation (C90, C ISO, formellement ISO/CEI 9899:1990). ANSI C est une évolution du C K&R qui reste extrêmement compatible. Elle reprend quelques idées de C++, notamment la notion de prototype et les qualificateurs de type[2].

Entre 1994 et 1996, le groupe de travail de l'ISO (ISO/CEI JTC1/SC22/WG14) a publié deux correctifs et un amendement à C90 : ISO/CEI 9899/COR1:1994 Technical Corrigendum 1, ISO/CEI 9899/AMD1:1995 Intégrité de C et ISO/CEI 9899/COR1:1996 Technical Corrigendum 2. Ces changements assez modestes sont parfois appelés C89 avec amendement 1, ou C94 / C95[3],[4]. Trois fichiers d'entêtes ont été ajoutés, dont deux concernant les caractères larges et un autre définissant un certain nombre de macros en rapport avec la norme de caractères ISO 646.

En 1999, une nouvelle évolution du langage est normalisée par l'ISO : C99 (formellement ISO/CEI 9899:1999). Les nouveautés portent notamment sur les tableaux de taille variable, les pointeurs restreints, les nombres complexes, les littéraux composés, les déclarations mélangées avec les instructions, les fonctions inline, le support avancé des nombres flottants, et la syntaxe de commentaire de C++. La bibliothèque standard du C99 a été enrichie de six fichiers d'en-tête depuis la précédente norme.

En 2011, l'ISO ratifie une nouvelle version du standard[5] : C11, formellement ISO/CEI 9899:2011. Cette évolution introduit notamment le support de la programmation multi-thread, les expressions à type générique, et un meilleur support d'Unicode.

## Caractéristiques générales[ modifier | modifier le code]

C'est un langage de programmation impératif et généraliste. C est qualifié de langage de bas niveau dans le sens où chaque instruction du langage est conçue pour être compilée en un nombre d'instructions machine assez prévisible en termes d'occupation mémoire et de charge de calcul. En outre, il propose un éventail de types entiers et flottants conçus pour pouvoir correspondre directement aux types de donnée supportés par le processeur. Enfin, il fait un usage intensif des calculs d'adresse mémoire avec la notion de pointeur.

Hormis les types de base, C supporte les types énumérés, composés, et opaques. Il ne propose en revanche aucune opération qui traite directement des objets de plus haut niveau (fichier informatique, chaîne de caractères, liste…). Ces types plus évolués doivent être traités en manipulant des pointeurs et des types composés. De même, le langage ne propose pas en standard la gestion de la programmation orientée objet, ni de système de gestion d'exceptions. Il existe des fonctions standards pour gérer les entrées-sorties et les chaîne de caractères, mais contrairement à d'autres langages, aucun opérateur spécifique pour améliorer l'ergonomie. Ceci rend aisé le remplacement des fonctions standards par des fonctions spécifiquement conçues pour un programme donné.

Ces caractéristiques en font un langage privilégié quand on cherche à maîtriser les ressources matérielles utilisées, le langage machine et les données binaires générées par les compilateurs étant relativement prévisibles. Ce langage est donc extrêmement utilisé dans des domaines comme la programmation embarquée sur microcontrôleurs, les calculs intensifs, l'écriture de systèmes d'exploitation et les modules où la rapidité de traitement est importante. Il constitue une bonne alternative au langage d'assemblage dans ces domaines, avec les avantages d'une syntaxe plus expressive et de la portabilité du code source. Le langage C a été inventé pour écrire le système d'exploitation UNIX, et reste utilisé pour la programmation système. Ainsi le noyau de grands systèmes d'exploitation comme Windows et Linux sont développés en grande partie en C.

En contrepartie, la mise au point de programmes en C, surtout s'ils utilisent des structures de données complexes, est plus difficile qu'avec des langages de plus haut niveau. En effet, dans un souci de performance, le langage C impose à l'utilisateur de programmer certains traitements (libération de la mémoire, vérification de la validité des indices sur les tableaux…) qui sont pris en charge automatiquement dans les langages de haut niveau.

Dépouillé des commodités apportées par sa bibliothèque standard, C est un langage simple, et son compilateur l'est également. Cela se ressent au niveau du temps de développement d'un compilateur C pour une nouvelle architecture de processeur : Kernighan et Ritchie estimaient qu'il pouvait être développé en deux mois car « on s'apercevra que les 80 % du code d'un nouveau compilateur sont identiques à ceux des codes des autres compilateurs existant déjà. »[6].

### Qualités et défauts[ modifier | modifier le code]

C'est un des langages les plus utilisés car :

- il existe depuis le début des années 1970 ;
- il est fondé sur un standard ouvert ;
- de nombreux informaticiens le connaissent ;
- étant du plus bas niveau portable possible, il permet la minimisation de l'allocation mémoire nécessaire et la maximisation de la performance, notamment par l'utilisation de pointeurs ;
- des compilateurs et bibliothèques logicielles existent sur la plupart des architectures ;
- il a influencé de nombreux langages plus récents dont C++, Java et PHP ; sa syntaxe en particulier est largement reprise ;
- il met en œuvre un nombre restreint de concepts, ce qui facilite sa maîtrise et l'écriture de compilateurs simples et rapides ;
- il ne spécifie pas rigidement le comportement du fichier exécutable produit, ce qui aide à tirer parti des capacités propres à chaque ordinateur ;
- il permet l'écriture de logiciels qui n'ont besoin d'aucun support à l'exécution (ni bibliothèque logicielle ni machine virtuelle), au comportement prévisible en temps d'exécution comme en consommation de mémoire vive, comme des noyaux de système d'exploitation et des logiciels embarqués.

Ses principaux inconvénients sont :

- le peu de vérifications offertes à par les compilateurs d'origine (K&R C), et l'absence de vérifications à l'exécution, ce qui fait que des erreurs qui pourraient être automatiquement détectées lors du développement ne le sont que plus tard, souvent au prix d'un plantage du logiciel ;
  - des vérifications sont ajoutées avec le temps, mais elles restent partielles ;
- son approche de la modularité restée au niveau de ce qui se faisait au début des années 1970, et largement dépassée depuis par d'autres langages :
  - il ne facilite pas la programmation orientée objet ;
  - il ne permet pas de créer des espaces de noms ;
- la gestion d'exceptions très sommaire ;
- le support très limité de la généricité, malgré l’introduction des expressions à type générique en C11 ;
- les subtilités de l'écriture de programmes portables, car le comportement exact des exécutables dépend de l'ordinateur cible ;
- le support minimaliste de l'allocation de mémoire et des chaîne de caractères, ce qui oblige les programmeurs à s'occuper de détails fastidieux et sources de bugs ; il n'y a notamment pas de ramasse-miettes standard ;
- les bugs graves qui peuvent être causés par un simple manque d'attention du développeur ; tel le dépassement de tampon qui constitue une faille de sécurité informatique exploitable par les logiciels malveillants ;
- certaines erreurs ne peuvent être détectées automatiquement qu'à l'aide d'outils supplémentaires et non standardisés, comme lint et Valgrind.

### Aperçu de la syntaxe[ modifier | modifier le code]

#### Hello world[ modifier | modifier le code]

Le programme Hello world est proposé en exemple en 1978 dans The C Programming Language de Brian Kernighan et Dennis Ritchie. Créer un programme affichant hello world est depuis devenu l'exemple de référence pour présenter les bases d'un nouveau langage. Voici l'exemple original :

    main()
    {
        printf("hello, world\n");
    }

Il serait cependant plus correct de l’écrire comme suit :

    #include <stdio.h>

    void main()
    {
        printf("hello, world\n");
    }

- `#include <stdio.h>` inclut l'en-tête standard `<stdio.h>`, contenant les déclarations des fonctions d'entrées-sorties de la bibliothèque standard du C, dont la fonction `printf` utilisée ici.
- `void` est le type de retour de la fonction. Ici, void signifie que la fonction ne retourne pas de valeur.
- `main` est le nom de la fonction principale, aussi appelée point d'entrée (en) du programme.
- Les parenthèses après `main` indiquent que `main` est une fonction.
- Les accolades `{` et `}` entourent les instructions constituant le corps de la fonction `main`.
- `printf` est une fonction d'écriture dans la sortie standard (la console par défaut).
- Le caractère `"` délimite une chaîne de caractères ; `hello, world\n` dans ce cas.
- Les caractères `\n` sont une séquence d'échappement représentant le saut de ligne.
- Un point-virgule `;` termine l'instruction.

#### Évolution des pratiques[ modifier | modifier le code]

Le même programme, conforme à la norme ISO et suivant les bonnes pratiques contemporaines :

    #include <stdio.h>

    int main(void)
    {
        printf("hello, world\n");
        return 0;
    }

- `int` est le type renvoyé par la fonction `main`. Le type `int` est le type implicite en K&R C et en C89, et il était couramment omis du temps où l'exemple de Kernighan et Ritchie a été écrit. Ce n'est plus le cas en C99.
- Le mot clé `void` entre parenthèses signifie que la fonction n'a aucun paramètre. S'il est omis, la fonction peut recevoir n'importe quels paramètres. Du temps du K&R C, le compilateur ne vérifiait pas que les paramètres envoyés à l'appel d'une fonction correspondent aux paramètres attendus. Et le mot clé `void` n'existait pas.
- L'instruction `return 0;` indique que la fonction `main` retourne la valeur 0. Cette valeur est de type `int`, et correspond au `int` devant le `main`.

#### Brièveté de la syntaxe[ modifier | modifier le code]

La syntaxe de C a été conçue pour être brève. Historiquement, elle a souvent été comparée à celle de Pascal, langage impératif également créé dans les années 1970. Voici un exemple avec une fonction factorielle :

    /* En C (norme ISO) */
    int factorielle(int n) {
        return n > 1 ? n * factorielle(n - 1) : 1;
    }

    { En Pascal }
    function factorielle(n: integer) : integer
    begin
    	if n > 1 then factorielle := n * factorielle(n - 1)
    	else factorielle := 1
    end.

Là où Pascal utilise des mots clés `function`, `integer`, `begin`, `if`, `then`, `else` et `end`, C n'utilise que `int` et `return`, les autres mots clés étant remplacés par des parenthèses et accolades, ainsi que l'opérateur `?:`.

#### Langage d'expressions[ modifier | modifier le code]

La brièveté de C ne repose pas que sur la syntaxe. Le grand nombre d'opérateurs disponibles, le fait que la plupart des instructions contiennent une expression, que les expressions produisent presque toujours une valeur, et que les instructions de test se contentent de comparer la valeur de l'expression testée avec zéro, concourent à la brièveté du code source.

Voici l'exemple de fonction de copie de chaîne de caractères — dont le principe est de copier les caractères jusqu'à avoir copié le caractère nul, qui marque par convention la fin d'une chaîne en C — donné dans The C Programming Language, 2nd edition, p. 106 :

    void strcpy(char *s, char *t)
    {
        while (*s++ = *t++)
            ;
    }

La boucle `while` utilise un style d'écriture classique en C, qui a contribué à lui donner une réputation de langage peu lisible. L'expression `*s++ = *t++` contient : deux déréférencements de pointeur ; deux incrémentations de pointeur ; une affectation ; et la valeur affectée est comparée avec zéro par le `while`. Cette boucle n'a pas de corps, car toutes les opérations sont effectuées dans l'expression de test du `while`. On considère qu'il faut maîtriser ce genre de notation pour maîtriser C[7].

Pour comparaison, une version n'utilisant pas les opérateurs raccourcis ni la comparaison implicite à zéro donnerait :

    void strcpy(char *s, char *t)
    {
        while (*t != '\0') {
            *s = *t;
            s = s + 1;
            t = t + 1;
        }
        *s = *t;
    }

## Des sources à l'exécutable[ modifier | modifier le code]

### Sources[ modifier | modifier le code]

Édition d'un fichier source C avec l'éditeur de texte Jed.
Article détaillé : Code source.

Un programme écrit en C est généralement réparti en plusieurs fichiers sources, qui peuvent être compilés chacun séparément.

Les fichiers sources C sont des fichiers texte, généralement dans le codage des caractères du système hôte. Ils peuvent être écrits avec un simple éditeur de texte. Il existe de nombreux éditeurs, voire des environnements de développement intégrés (IDE), qui ont des fonctions spécifiques pour supporter l'écriture de sources en C.

L'usage est de donner les extensions de nom de fichier `.c` et `.h` aux fichiers source C. Les fichiers `.h` sont appelés fichiers d'en-tête, de l'anglais header. Ils sont conçus pour être inclus au début des fichiers source, et contiennent uniquement des déclarations.

Lorsqu'un fichier `.c` ou `.h` utilise un identificateur déclaré dans un autre fichier `.h`, alors il inclut ce dernier. Le principe généralement appliqué consiste à écrire un fichier `.h` pour chaque fichier `.c`, et à déclarer dans le fichier `.h` tout ce qui est exporté par le fichier `.c`.

La génération d'un exécutable à partir des fichiers sources se fait en plusieurs étapes, qui sont souvent automatisées à l'aide d'outils comme make, SCons, ou bien des outils spécifiques à un environnement de développement intégré. Les étapes menant des sources au fichier exécutable sont au nombre de quatre : précompilation, compilation, assemblage, édition de liens. Lorsqu'un projet est compilé, seuls les fichiers `.c` font partie de la liste des fichiers à compiler ; les fichiers `.h` sont inclus par les directives du préprocesseur contenues dans les fichiers source.

### Précompilation[ modifier | modifier le code]

Article détaillé : Préprocesseur.

Le préprocesseur C exécute des directives contenues dans les fichiers sources. Il les reconnaît au fait qu'elles sont en début de ligne, et commencent toutes avec le caractère croisillon `#`. Parmi les directives les plus courantes, il y a :

- `#include` pour l'inclusion ;
- `#define` pour la définition de macro ;
- `#if` pour commencer la compilation conditionnelle ;
- `#ifdef` équivalent de `#if defined()` ;
- `#endif` pour clore la compilation conditionnelle.

Outre l'exécution des directives, le préprocesseur remplace les commentaires par un espace blanc, et procède au remplacement des macros. Pour le reste, le code source est transmis tel quel au compilateur pour la phase suivante. Il faut toutefois que chaque `#include` dans le code source soit récursivement remplacé par le code source inclus. Ainsi, le compilateur reçoit un seul source du préprocesseur, qui constitue l'unité de compilation.

Voici un exemple de fichier source `copyarray.h` faisant un usage classique des directives du préprocesseur :

    #ifndef COPYARRAY_H
    #define COPYARRAY_H

    #include <stddef.h>

    void copyArray(int *, size_t);

    #endif

Les directives `#ifndef`, `#define` et `#endif` servent à garantir que le code à l'intérieur n'est compilé qu'une seule fois — alors que `COPYARRAY_H` n'est pas défini — même si le fichier est inclus plusieurs fois. La directive `#include <stddef.h>` inclut l'en-tête qui déclare le type `size_t` utilisé plus bas.

### Compilation[ modifier | modifier le code]

Article détaillé : Compilateur.

La phase de compilation consiste généralement en la génération du code assembleur. C'est la phase la plus intensive en traitements. Elle est accomplie par le compilateur proprement dit. Pour chaque unité de compilation, on obtient un fichier en langage d'assemblage.

Cette étape peut être divisée en sous-étapes :

- l'analyse lexicale, qui est la reconnaissance des mots clé du langage ;
- l'analyse syntaxique, qui analyse la structure du programme et sa conformité avec la norme ;
- l'optimisation de code ;
- l'écriture d'un code isomorphe à celui de l'assembleur (et parfois du code assembleur lui-même quand cela est demandé en option du compilateur).

Par abus de langage, on appelle compilation toute la phase de génération d'un fichier exécutable à partir des fichiers sources. Mais c'est seulement une des étapes menant à la création d'un exécutable.

Certains compilateurs C fonctionnent à ce niveau en deux phases, la première générant un fichier compilé dans un langage intermédiaire destiné à une machine virtuelle idéale (voir P-Code) portable d'une plate-forme à l'autre, la seconde convertissant le langage intermédiaire en langage d'assemblage dépendant de la plate-forme cible. D'autres compilateurs C permettent de ne pas générer de langage d'assemblage, mais seulement le fichier compilé en langage intermédiaire, qui sera interprété ou compilé automatiquement en code natif à l'exécution sur la machine cible (par une machine virtuelle qui sera liée au programme final).

### Assemblage[ modifier | modifier le code]

Article détaillé : Assemblage (informatique).

Cette étape consiste en la génération d'un fichier objet en langage machine pour chaque fichier de code assembleur. Les fichiers objet sont généralement d’extension `.o` sur Unix, et `.obj` avec les outils de développement pour MS-DOS, Microsoft Windows, VMS, CP/M… Cette phase est parfois regroupée avec la précédente par établissement d'un flux de données interne sans passer par des fichiers en langage intermédiaire ou langage d'assemblage. Dans ce cas, le compilateur génère directement un fichier objet.

Pour les compilateurs qui génèrent du code intermédiaire, cette phase d'assemblage peut aussi être totalement supprimée : c'est une machine virtuelle qui interprétera ou compilera ce langage en code machine natif. La machine virtuelle peut être un composant du système d'exploitation ou une bibliothèque partagée.

### Édition des liens[ modifier | modifier le code]

Article détaillé : Édition de liens.

L'édition des liens est la dernière étape, et a pour but de réunir tous les éléments d'un programme. Les différents fichiers objet sont alors réunis, ainsi que les bibliothèques statiques, pour ne produire qu'un fichier exécutable.

Le but de l'édition de liens est de sélectionner les éléments de code utiles présents dans un ensemble de codes compilés et de bibliothèques, et de résoudre les références mutuelles entre ces différents éléments afin de permettre à ceux-ci de se référencer directement à l'exécution du programme. L'édition des liens échoue si des éléments de code référencés manquent.

## Éléments du langage[ modifier | modifier le code]

### Éléments lexicaux[ modifier | modifier le code]

Le jeu de caractères ASCII suffit pour écrire en C. Il est même possible, mais inusité, de se restreindre au jeu de caractères invariants de la norme ISO 646, en utilisant des séquences d'échappement appelées trigraphe. En général, les sources C sont écrits avec le jeu de caractères du système hôte. Il est toutefois possible que le jeu de caractères d'exécution ne soit pas celui du source.

Le C est sensible à la casse. Les caractères blancs (espace, tabulation, fin de ligne) peuvent être librement utilisés pour la mise en page, car ils sont équivalent à un seul espace dans la plupart des cas.

### Fonctions[ modifier | modifier le code]

Les fonctions en C sont des blocs d'instructions, recevant un ou plusieurs arguments et pouvant retourner une valeur. Si une fonction ne retourne aucune valeur, le mot-clé `void` est utilisé. Une fonction peut également ne recevoir aucun argument. Le mot-clé `void` est également utilisé dans ce cas.

    // Fonction ne retournant aucune valeur
    void afficher(int a)
    {
        printf("%d", a);
    }

    // Fonction retournant un entier
    int somme(int a, int b)
    {
        return a + b;
    }

    // Fonction sans aucun argument
    int saisir(void)
    {
        int a;
        scanf("%d", &a);
        return a;
    }

#### Prototype[ modifier | modifier le code]

Un prototype consiste à déclarer une fonction sans les instructions qui la compose. Un prototype se termine par un point-virgule. Leur intérêt est de pouvoir utiliser une fonction avant de devoir écrire ses instructions.

    // Prototype de saisir()
    int saisir();

    // Fonction utilisant saisir()
    int somme()
    {
        int a = saisir(), b = saisir();
        return a + b;
    }

    // Définition de saisir()
    int saisir()
    {
        int a;
        scanf("%d", &a);
        return a;
    }

Généralement, tous les prototypes sont écris dans des fichiers .h, et les fonctions sont définies dans un fichier .c classique.

### Mots clés[ modifier | modifier le code]

Le C89 compte 32 mots clés, dont cinq qui n'existaient pas en K&R C, et qui sont par ordre alphabétique :

  `auto`, `break`, `case`, `char`, `const` (C89), `continue`, `default`, `do`, `double`, `else`, `enum` (C89), `extern`, `float`, `for`, `goto`, `if`, `int`, `long`, `register`, `return`, `short`, `signed` (C89), `sizeof`, `static`, `struct`, `switch`, `typedef`, `union`, `unsigned`, `void` (C89), `volatile` (C89), `while`.

Ce sont des termes réservés qui ne doivent pas être utilisés autrement.

La révision C99[8] en ajoute cinq :

  `_Bool`, `_Complex`, `_Imaginary`, `inline`, `restrict`.

Ces nouveaux mots-clés commencent par une majuscule préfixée d’un underscore afin de maximiser la compatibilité avec les codes existants. Des en-têtes de la bibliothèque standard fournissent les alias `bool` (`<stdbool.h>`), `complex` et `imaginary` (`<complex.h>`).

La dernière révision, C11[9], introduit encore sept nouveaux mots-clés avec les mêmes conventions :

  `_Alignas`, `_Alignof`, `_Atomic`, `_Generic`, `_Noreturn`, `_Static_assert`, `_Thread_local`.

Les en-têtes standards `<stdalign.h>`, `<stdnoreturn.h>`, `<assert.h>` et `<threads.h>` fournissent respectivement les alias `alignas` et `alignof`, `noreturn`, `static_assert`, et `thread_local`.

### Instructions du préprocesseur[ modifier | modifier le code]

Le préprocesseur du langage C offre les directives suivantes :

  `#include`, `#define`, `#pragma` (C89), `#if`, `#ifdef`, `#ifndef`, `#elif` (C89), `#else`, `#endif`, `#undef`, `#line`, `#error`.

### Types[ modifier | modifier le code]

Le langage C comprend de nombreux types de nombres entiers, occupant plus ou moins de bits. La taille des types n'est que partiellement standardisée : le standard fixe uniquement une taille minimale et une magnitude minimale. Les magnitudes minimales sont compatibles avec d'autres représentations binaires que le complément à deux, bien que cette représentation soit presque toujours utilisée en pratique. Cette souplesse permet au langage d'être efficacement adapté à des processeurs très variés, mais elle complique la portabilité des programmes écrits en C.

Chaque type entier a une forme « signée » pouvant représenter des nombres négatifs et positifs, et une forme « non signée » ne pouvant représenter que des nombres naturels. Le type `char`, généralement utilisé pour représenter un caractère, est un type entier comme les autres, si ce n'est que, selon l'implémentation, il équivaut à `signed char` ou à `unsigned char`.

Types entiers, en ordre croissant
Type | Taille | Magnitude signed (magnitude minimale exigée par le standard[10]) | Magnitude unsigned (magnitude minimale exigée par le standard[10])
--- | --- | --- | ---
`char`, `unsigned char`, `signed char` (C89) | ≥ 8 bits | -127 à 127 | 0 à 255 (0xFF en hexadécimal noté avec le préfixe `0x` de la syntaxe de C)
`short` (identique à `signed short`), `unsigned short` | ≥ 16 bits | -32 767 à +32 767 | 0 à 65 535 (0xFFFF)
`int` (identique à `signed int`), `unsigned int` | ≥ 16 bits (taille d'un mot machine) | -32 767 à +32 767 | 0 à 65 535 (0xFFFF)
`long` (identique à `signed long`), `unsigned long` | ≥ 32 bits | -2 147 483 647 à +2 147 483 647 | 0 à 4 294 967 295 (0xFFFFFFFF)
`long long` (identique à `signed long long`), `unsigned long long` (C99) | ≥ 64 bits | -9 223 372 036 854 775 807 à +9 223 372 036 854 775 807 | 0 à 18 446 744 073 709 551 615 (0xFFFFFFFFFFFFFFF)

Le type `enum` est un type énuméré.

Il existe des types de nombres à virgule flottante, de précision, donc de longueur en bits, variable ; en ordre croissant :

Types décimaux, en ordre croissant
Type | Précision | Magnitude
--- | --- | ---
`float` | ≥ 6 chiffres décimaux | environ 10-37 à 10+37
`double` | ≥ 10 chiffres décimaux | environ 10-37 à 10+37
`long double` | ≥ 10 chiffres décimaux | environ 10-37 à 10+37
`long double` (C89) | ≥ 10 chiffres décimaux |

C99 a ajouté `float complex`, `double complex` et `long double complex`, représentant les nombres complexes associés.

Types élaborés :

- `struct`, `union`, `*` pour les pointeurs ;
- `[`… `]` pour les tableaux ;
- `(`… `)` pour les fonctions.

Les versions du langage antérieures à C99 ne proposent pas de type booléen, mais il est possible d'en définir un :

    enum boolean {false, true};
    typedef enum boolean bool;

ou, en version condensée :

    typedef enum boolean {false, true} bool;

C99 ajoute le type _Bool.

#### Le type `void *`[ modifier | modifier le code]

Le type `void *` est un pointeur sur un type indéterminé. Il permet par exemple à une fonction de retourner n'importe quel type de données. Il faut néanmoins penser à convertir le pointeur `void *` en pointeur typé (opération appelées également type casting) pour que les opérations sur ce pointeur soient justes. Il est par exemple utilisé par la fonction malloc, pour retourner l'adresse du bloc adressé.

### Structures[ modifier | modifier le code]

C supporte les types composés avec la notion de structure. Pour définir une structure, il faut utiliser le mot-clé `struct` suivit du nom de la structure. Les membres doivent ensuite être déclarés entre accolades. Comme toute déclaration, un point-virgule termine le tout.

    /* Déclaration de la structure personne */
    struct Personne
    {
        int age;
        char *nom;
    };

Pour accéder aux membre d'une struture, il faut utiliser l'opérateur `.`.

    int main()
    {
        struct Personne p;
        p.nom = "Albert";
        p.age = 46;
    }

Les fonctions peuvent recevoir des pointeurs vers des structures. Ils fonctionnent avec la même syntaxe que les pointeurs classiques. Néanmoins, l'opérateur `->` doit être utilisé sur le pointeur pour accéder aux champs de la structure. Il est également possible de déréférencer le pointeur pour ne pas utiliser cet opérateur, et toujours utiliser l'opérateur `.`

    void anniversaire(struct Personne * p)
    {
        p->age++;
        printf("Joyeux anniversaire %s !", (*p).nom);
    }

    int main()
    {
        struct Personne p;
        p.nom = "Albert";
        p.age = 46;
        anniversaire(&p);
    }

### Commentaire[ modifier | modifier le code]

Dans les versions de C antérieures à C99, les commentaires devaient commencer par une barre oblique et un astérisque (« /* ») et se terminer par un astérisque et une barre oblique. Tout ce qui est compris entre ces symboles est du commentaire, saut de ligne compris :

    /* Ceci est un commentaire
       sur deux lignes
       ou plus */

La norme C99 a repris de C++ les commentaires de fin de ligne, introduits par deux barres obliques et se terminant avec la ligne :

    // Commentaire jusqu'à la fin de la ligne

### Structures de contrôle[ modifier | modifier le code]

La syntaxe des différentes structures de contrôle existantes en C est largement reprise dans plusieurs autres langages, comme le C++ bien sûr, mais également Java, C#, PHP ou encore JavaScript.

Les trois grands types de structures sont présents :

- les tests (également appelés branchements conditionnels) avec :
  - `if (expression) instruction`
  - `if (expression) instruction else instruction`
  - `switch (expression) instruction`, avec `case` et `default` dans l'instruction
- les boucles avec :
  - `while (expression) instruction`
  - `for (expression_optionnelle ; expression_optionnelle ; expression_optionnelle) instruction`
  - `do instruction while (expression)`
- les sauts (branchements inconditionnels) :
  - `break`
  - `continue`
  - `return expression_optionnelle`
  - `goto étiquette`

### Comportements ambigus[ modifier | modifier le code]

La norme du langage C laisse la définition exacte du comportement de plusieurs opérations au choix du concepteur du compilateur. Ces comportements sont donc définis par l'implémentation. Cette propriété de C permet au compilateur d'utiliser directement les instructions proposées par le processeur, donc de compiler des programmes exécutables courts et efficaces. En contrepartie, c'est parfois la cause de bugs de portabilité des codes source écrits en C. Prenons pour exemple[11] la division entière d'un nombre négatif : -5 / 3. Alors que Fortran, Pascal et Ada spécifient un résultat de -1, et que Modula-3 spécifie un résultat de -2, C[12] garantit simplement que la valeur absolue du reste est strictement inférieure à la valeur absolue du diviseur[13]. La seule garantie dans cet exemple est donc que le résultat sera -2 ou -1.

Pour le programmeur et l'efficacité de C, le plus important est sans doute le fait que les tailles des types de données de base ne doivent respecter que des garanties minimales. Ainsi, le type `int` correspondant au mot machine peut avoir une taille de 16 bits sur un processeur 16 bits et une taille de 64 bits sur un processeur 64 bits.

Outre les comportements laissés au choix de l'implémentation, des constructions syntaxiquement valables ont un comportement lors de l'exécution complètement indéfini. En plus de la classique division par zéro, on peut signaler l'affectation multiple d'une variable dans la même expression, avec l'exemple[14] :

     i = i++; /* Comportement indéfini. */

Les meilleurs compilateurs décèlent certaines constructions problématiques et peuvent les signaler, mais aucun ne prétend à l'exhaustivité.

## Bibliothèques logicielles[ modifier | modifier le code]

### La bibliothèque standard[ modifier | modifier le code]

Article détaillé : Bibliothèque standard du C.

La bibliothèque standard normalisée, disponible avec toutes les implémentations, présente la simplicité liée à un langage bas-niveau. Voici une liste de quelques en-têtes déclarant des types et fonctions de la bibliothèque standard :

- `<assert.h>` : pour un diagnostic de conception lors de l'exécution (`assert`)
- `<ctype.h>` : tests et classification des caractères (`isalnum`, `tolower`)
- `<errno.h>` : gestion minimale des erreurs (déclaration de la variable `errno`)
- `<math.h>` : fonctions mathématiques de base (`sqrt`, `cos`) ; nombreux ajouts en C99
- `<signal.h>` : gestion des signaux (`signal` et `raise`)
- `<stddef.h>` : définitions générales (déclaration de la constante `NULL`)
- `<stdio.h>` : pour les entrées/sorties de base (`printf`, `scanf`)
- `<stdlib.h>` : fonctions générales (`malloc`, `rand`)
- `<string.h>` : manipulation des chaînes de caractères (`strcmp`, `strlen`)
- `<time.h>` : manipulation du temps (`time`, `ctime`)

La bibliothèque standard normalisée n'offre aucun support de l'interface graphique, du réseau, des entrées/sorties sur port série ou parallèle, des systèmes temps réel, des processus, ou encore de la gestion avancée des erreurs (comme avec des exceptions structurées). Cela pourrait restreindre d'autant la portabilité pratique des programmes qui ont besoin de faire appel à certaines de ces fonctionnalités, sans l'existence de très nombreuses bibliothèques portables et palliant ce manque ; dans le monde UNIX, ce besoin a aussi fait émerger une autre norme, POSIX.1.

### Les bibliothèques externes[ modifier | modifier le code]

Le langage C étant un des langages les plus utilisés en programmation, de nombreuses bibliothèques ont été créées pour être utilisées avec le C. Fréquemment, lors de l'invention d'un format de données, une bibliothèque ou un logiciel de référence en C existe pour manipuler le format. C'est le cas pour libjpeg, libpng, Expat, les décodeur de référence MPEG, libsocket, etc.

## Exemples[ modifier | modifier le code]

Voici quelques exemples présentant très succinctement quelques propriétés du C. Pour plus d'information, voir le WikiLivre "Programmation C".

### Allocation mémoire[ modifier | modifier le code]

La structure `int_list` représente un élément d'une liste chaînée, contenant des données de type `int`. Les deux fonctions qui suivent (`insert_next` et `remove_next`) servent à ajouter et supprimer un élément de la liste.

    /* La gestion de la mémoire n'est pas intégrée au langage
       mais assurée par des fonctions de la bibliothèque standard. */
    #include <stdlib.h>

    struct int_list {
        struct int_list *next; /* pointeur sur l'élément suivant */
        int value;             /* valeur de l'élément */
    };

    /*
     * Ajouter un élément à la suite d'un autre.
     * node : élément après lequel ajouter le nouveau
     * value : valeur de l'élément à ajouter
     * Retourne : adresse de l'élément ajouté, ou NULL en cas d'erreur.
     */
    struct int_list *insert_next(struct int_list *node, int value) {
        /* Allocation de la mémoire pour un nouvel élément. */
        struct int_list *const new_next = malloc(sizeof *new_next);

        /* Si l'allocation a réussi, alors insérer new_next entre node
           et node->next. */
        if (new_next) {
            new_next->next = node->next;
            node->next = new_next;
            new_next->value = value;
        }

        return new_next;
    }

    /*
     * Supprimer l'élément suivant un autre.
     * node : élément dont le suivant est supprimé
     * Attention : comportement indéterminé s'il n'y pas d'élément suivant !
     */
    void remove_next(struct int_list *node) {
        struct int_list *const node_to_remove = node->next;

        /* Retire l'élément suivant de la liste. */
        node->next = node->next->next;
        /* Libère la mémoire occupée par l'élément suivant. */
        free(node_to_remove);
    }

Dans cet exemple, les deux fonctions essentielles sont `malloc` et `free`. La première sert à allouer de la mémoire, le paramètre qu'elle reçoit est le nombre de bytes que l'on désire allouer et elle retourne l'adresse du premier byte qui a été alloué, sinon elle retourne NULL. `free` sert à libérer la mémoire qui a été allouée par `malloc`.

## Références[ modifier | modifier le code]

1. ↑ (en) « The Development of the C Language » [archive], Dennis M. Ritchie.
2. ↑ (en) Brian Kernighan et Dennis Ritchie, The C Programming Language [détail des éditions], pp. 260,261
3. ↑ (en), Samuel P. Harbison III, Guy L. Steel Jr., A Reference Manual, fifth edition, Upper Saddle River, Prentice Hall, 2002, p. 4, (ISBN 0-13-089592-X)
4. ↑ (en), Thomas Wolf, The New ISO Standard for C (C9X), 2000
5. ↑ http://www.iso.org/iso/fr/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=57853 [archive]
6. ↑ Brian Kernighan et Dennis Ritchie (trad. Thierry Buffenoir), Le langage C [« The C Programming Language »], Paris, Masson,‎ 1983, 1e éd., 218 p. [détail des éditions] (ISBN 2-225-80068-5), p. 4
7. ↑ (en) Brian Kernighan et Dennis Ritchie, The C Programming Language, Prentice Hall,‎ 1988, 2e éd., 272 p. [détail des éditions] (ISBN 0-13-110362-8), p. 106.
8. ↑ « ISO/CEI 9899:TC3, Section 6.4.1: Keywords » [archive], Organisation internationale de normalisation JTC1/SC22/WG14,‎ 7 septembre 2007
9. ↑ « ISO/CEI 9899:201x, Section 6.4.1: Keywords » [archive], International Organization for Standardization JTC1/SC22/WG14,‎ 12 avril 2011
10. ↑ a et b « Sizes of integer types », ISO-IEC 9899, 5.2.4.2.1
11. ↑ donné dans Computer Architecture, a Quantitative Approach, 2e édition, de David A. Patterson et John L. Hennessy, Appendix A-12
12. ↑ La révision en 1999 de la norme spécifie explicitement que le résultat soit -1 [6.5.5 alinéa 6].
13. ↑ (en) Brian Kernighan et Dennis Ritchie, The C Programming Language, Prentice Hall,‎ 1988, 2e éd., 272 p. [détail des éditions] (ISBN 0-13-110362-8), p. 205
14. ↑ (en) comp.lang.c FAQ list · Question 3.3 [archive]

## Voir aussi[ modifier | modifier le code]

Sur les autres projets Wikimedia :

- La programmation en C, sur Wikiversity
- Le langage C, sur Wikibooks

### Articles connexes[ modifier | modifier le code]

- Bibliothèque standard du C
- Alignement de données
- International Obfuscated C Code Contest

#### Quelques programmes célèbres écrits en C[ modifier | modifier le code]

- UNIX
- La suite de compilateurs GNU Compiler Collection (GCC)
- Le noyau Linux
- Le noyau de Microsoft Windows
- GNOME

### Bibliographie[ modifier | modifier le code]

- (en) Brian Kernighan et Dennis Ritchie, The C Programming Language [détail des éditions]
- The international standardization working group for the programming language C,
  - (en) ISO/CEI 9899:TC2 WG14/N1124, « Committee Draft », 6 mai 2005 [lire en ligne]
    Le dernier brouillon de la norme ISO C99 incluant le Technical Corrigendum 2
  - (en) ISO/CEI 9899:TC3 WG14/N1256, « Committee Draft », 7 septembre 2007 [lire en ligne]
    Le dernier brouillon de la norme ISO C99 incluant le Technical Corrigendum 3
- (en) Ivor Horton, Beginning C, Apress, 2006, (ISBN 978-1-59059-735-4)
- Jean-Michel Léry, Le langage C, Pearson Education, 2005, (ISBN 978-2-7440-7086-0)
- Achille Braquelaire, Méthodologie de la programmation en C, Dunod,‎ 2005 [détail de l’édition], (ISBN 978-2-10-049018-9)
- Claude Delannoy, Programmer en langage C - Cours et exercices corrigés, Eyrolles, 11e tirage - 2006, (ISBN 978-2-212-11072-2)
- Mathieu Nebra, Apprenez à programmer en C - 2e édition, Édition Site du Zéro - 2009, (ISBN 979-1090085008)
- Éric Berthomier et Daniel Schang, Le C en 20 heures, Framasoft, coll. « Framabook » (no 6),‎ 2013, 3e éd. (1re éd. 2010), 196 p. (ISBN 978-2-9539187-7-9, présentation en ligne)

### Liens externes[ modifier | modifier le code]

- (fr) Catégorie Langage C de l’annuaire DMOZ

[masquer] v · m Langages de programmation
Orientés objet | ActionScript · AppleScript · C++ · C# · CoffeeScript · D · Delphi · Eiffel · Groovy · Java · JavaScript · Lisaac · Logo · Objective-C · PHP · Python · Ruby · Scala · Simula · Smalltalk · Visual Basic
Impératifs | Algol · APL · ASP · Assembleur · BASIC · BCPL · Shell Unix · C · COBOL · Natural · Forth · Fortran · Go · Limbo · Lua · Modula-2 · NQC · NXC · OPL · Pascal · Perl · PHP · Rust · PL/I · Tcl · Windows PowerShell · WLangage
Fonctionnels | Haskell · Lisp · Common Lisp · ML · OCaml · Gallina · F# · Standard ML · Opa · Scheme · XSLT
Déclaratifs | Clips · Prolog · ASP
Concurrents | Ada · Erlang
Conception · Codage · Tests · Optimisations

- Portail de la programmation informatique

Ce document provient de « https://fr.wikipedia.org/w/index.php?title=C_(langage)&oldid=117831996 ».
Catégories :

- Langage C
- Langage de programmation
- Norme ISO

| [+]
Catégories cachées :

- Article contenant un appel à traduction en anglais
- Portail:Programmation informatique/Articles liés
- Portail:Informatique/Articles liés