Le langage C

, par MiKaël Navarro

Le but n’est pas ici de récrire un tutoriel sur le C mais de donner les bases
afin d’aborder, dans un futur article, une méthode de programmation basée sur la
notion d’interface.

Genèse

Le langage C fut créé en 1972 dans les laboratoires de Bell AT&R par Dennis
Ritchie (héritié du langage B de Kenneth Thompson). C’est un langage de
programmation impératif faiblement typé conçu pour la programmation système
(qualifié de bas niveau).

Le langage C a été utilisé pour rendre le système d’exploitation UNIX plus
portable (cependant, le portage peut poser des problèmes notamment en ce qui
concerne la taille des mots).

En 1983, l’ANSI [1] débuta des travaux
aboutirent en 1989 à l’approbation de la norme dite ANSI C ou C89.

Avant cette normalisation, en 1978 le langage C était stabilisé par une annexe
du livre de Brian Kernignan et Dennis Ritchie, connue sous le nom de K&R.
ANSI C est une évolution du C K&R qui reste extrêmement compatible.

En 1990, cette norme a également été adoptée par l’Organisation internationale
de normalisation (C ISO).
Et en 1999, une nouvelle évolution du langage est normalisée par l’ISO : C99.

Hello World !

La syntaxe de C a été conçue pour être brève.
Programme Hello world proposé en exemple en 1978 dans The C Programming Language
de Brian W. Kernighan et Dennis M. Ritchie :

Le même programme, conformément à la norme ISO :

 La première ligne indique d’utiliser la lib standard ainsi que la bibliothèque
d’entrées / sorties.
 main est le nom de la fonction principale, aussi appelée point d’entrée.
La signature de cette fonction nous indique qu’elle retourne un entier (int)
et ne prend aucun paramètre (void).
 Les accolades constituent le corps de la fonction.
 La fonction printf est chargée de l’affichage à l’écran du fameux
"hello, world" (suivi d’un retour à la ligne).
 Enfin, la norme ISO demande que le programme renvoi un entier comme statut de
retour (0 signifiant aucune erreur).

Compilation

Il nous reste maintenant à exécuter notre premier programme.
Il nous faut pour cela traduire ce programme C en langage machine grâce au
compilateur :

En fait les étapes menant des sources au fichier exécutable sont au nombre de
quatre :

  1. Pré-compilation : opérations sur les fichiers sources, inclusion de fichiers,
    remplacements de textes, ...
  2. Compilation : analyse lexicale et syntaxique, puis génération du code
    assembleur.
  3. Assemblage : génération d’un fichier objet (.o) en langage machine.
  4. Édition de liens : réunion des fichiers objets et librairies statiques dans
    un seul exécutable.

Ça marche !

Éléments du langage

 Instructions du pré-compilateur

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

Liste des constantes usuelles :
__FILE__ : fichier actuel ; __LINE__ : ligne actuelle ; __FUNCTION__ : fonction actuelle (extension non standard) ; __func__ (C99) : alternative à __FUNCTION__ pour certains compilateurs ; __DATE__ : date de compilation ; __TIME__ : heure de compilation.

 Mots clefs

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

 Types

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.

Types entiers, en ordre croissant :

  • char, unsigned char, signed char (C89) : taille ≥ 8 bits
  • short (identique à signed short), unsigned short : taille ≥ 16 bits
  • int (identique à signed int), unsigned int : taille ≥ 16 bits (taille d’un mot machine)
  • long (identique à signed long), unsigned long : taille ≥ 32 bits
  • (C99) long long (identique à signed long long), unsigned long long : taille ≥ 64 bits
  • enum : types énumérés

Types réels, en ordre croissant :

  • float : précision ≥ 6 chiffres décimaux
  • double : précision ≥ 10 chiffres décimaux
  • (C89) long double : précision ≥ 10 chiffres décimaux

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

 Structure de données

Le langage C permet aussi de définir des types de données composées, c-à-d
contenant des champs, chacun ayant un certain type :

struct nom {
 type_1 nom_1;
 type_2 nom_2;
 ...
 type_n nom_n;
};

Pour déclarer une variable structure et y accéder :

  • Création de types de données

Le mor clé typedef permet de définir de nouveaux types de données :

typedef struct nom {
 type_1 nom_1;
 type_2 nom_2;
 ...
 type_n nom_n;
} nom;

Cela nous permet de déclarer une variable x de type nom :

nom x;

 Variables

Une variable est représentée en C par un nom (lettres de l’alphabet, chiffres et
la lettre _).
Le type de la variable va déterminer la quantité de mémoire nécessaire pour
stocker son contenu.

  • Affectation

Le langage C définit l’opérateur = pour donner une valeur à une variable.
L’expression à droite du signe = est évaluée et son résultat est placé dans la
variable.

  • Bloc d’instructions

Un bloc de code est délimité par des accolades et contient deux parties :
les déclarations et les instructions. Le plus petit bloc est "{}".
La partie des déclarations déclare ou définit des variables locales qui ne sont
accessibles qu’aux déclarations et aux instructions situées sous elles, dans le
même bloc ou les blocs inclus.
Les déclarations et les instructions sont exécutées de gauche à droite et du
haut vers le bas.

  • Portée des variables

Principalement, nous pouvons déclarer des variables à deux endroits, à
l’intérieur d’un bloc délimité par des accolades ou à l’extérieur ; A
l’extérieur de tout bloc, on dit que c’est une variable globale (accessible de
n’importe quel endroit du programme se situant en dessous d’elle). Au début
d’un bloc elle est locale à ce bloc.

 Structures de contrôle

  • Tests
if (expression) {
 instructions
}else if (expression) {
 instructions
} else {
 instructions
}
switch (expression) {
 case valeur_1: expressions_1;
 case valeur_2: expressions_2;
 ...
 case valeur_n: expressions_n;
 default: expressions_d
}

Le switch évalue l’expression, puis cherche si une clause correspond. Alors
les expressions sont exécutées ainsi que toutes les expressions suivantes.
Si aucune clause ne correspond, la clause default est sélectionnée.

Si on souhaite n’exécuter que les expressions correspondant à la clause
sélectionnée, il faut explicitement sortir du switch avec l’instruction break ;

Les valeurs après les cases doivent être des constantes (nombres, caractères
ou valeurs énumération).

  • Itérations
    • while (condition) instruction

Tant que la condition retourne un résultat non nul, l’instruction est
exécutée.
A noter que le langage C ne possède pas de type booléen : n’importe quel type de
valeur peut jouer ce rôle. Une valeur nulle est considérée comme fausse, toutes
autres valeurs sont considérées comme vraies.

    • do instruction while (condition)

Dans ce cas, l’instruction est d’abors exécuté, puis la condition est
évaluée.

    • for (init; test; post) expression

L’expression init est exécuté au début de l’itération, puis les test est
évalué et si son résultat est nul, l’itération se termine. Sinon, l’expression
est évalué ainsi que l’expression post, puis l’itération recommence par
l’évaluation du test.

 Les fonctions

La définition d’une fonction comprend deux parties : le prototype et le corps.
Le prototype contient le type de la valeur de retour de la fonction, le nom et
la liste des paramètres. Le coprs de la fonction est un bloc :
type nom(paramètres) {bloc}

Exemple :

On ne peut définir des fonctions à l’intérieur d’un bloc, toutes les fonctions
sont donc globales (nous verrons plus tard comment restrindre cette portée).

  • Prototype des fonctions

Un prototype de fonction consiste dans le type de la valeur de retour, le nom de
la fonction et ses paramètres, le tout suivi d’un point-virgule.

Bibliothèque standard

 Entrée / sorties

La principale fonction qui permet d’afficher des messages à l’écran est printf.
C’est une fonction dont le nombre d’arguments est variable. Le premier argument
est obligatoirement une chaîne de caractère appelé chaîne de formatage :

Le langage C est très permissif : il effectue peu de contrôles ; Aussi il ne
vérifiera pas le nombre d’arguments supplémentaires fournit :

La principale fonction de lecture de C est scanf.
C’est aussi une fonction ayant un nombre d’arguments variable dont le premier
est obligatoirement une chaîne de format. Dans cette chaîne, les séquences %
doivent correspondre à des variables qui recevrons les valeurs lues. Ces
variables doivent être préfixés par le caractère & :

P.-S.

Je ne m’attarderai pas plus sur les détails du langage, je vous re-dirige pour
cela sur le K&R
et le wiki book sur C...

Notes

[1American National Standards Institute