Toute commande du préprocesseur commence :
en début de ligne ;
par un signe dièse (#).
Les commandes sont les suivantes :
L'inclusion de fichier permet de factoriser du texte commun à plusieurs autres fichiers (par exemple des déclarations de types, de constantes, de fonctions, etc.). Le texte commun est mis en général dans un fichier portant l'extension .h (pour « header », fichier d'en-tête de programme).
Syntaxe :
#include "fichier"ou :
#include <fichier>
fichier est le nom du fichier à inclure. Lorsque son nom est entre guillemets, le fichier spécifié est recherché dans le répertoire courant (normalement le répertoire du programme). S'il est encadré de crochets, il est recherché d'abord dans les répertoires spécifiés en ligne de commande avec l'option -I, puis dans les répertoires du chemin de recherche des en-têtes du système (ces règles ne sont pas fixes, elles ne sont pas normalisées).
Le fichier inclus est traité lui aussi par le préprocesseur.
La signification de la ligne #include <stdio.h> au début de tous les programmes utilisant les fonctions scanf et printf devient alors claire. Si vous ouvrez le fichier stdio.h, vous y verrez la déclaration de toutes les fonctions et de tous les types de la librairie d'entrée - sortie standard. De même, les fonctions malloc et free sont déclarées dans le fichier d'en-tête stdlib.h et définies dans la librairie standard. L'inclusion de ces fichiers permet donc de déclarer ces fonctions afin de les utiliser.
Syntaxe :
#define texte remplacement
texte est le texte à remplacer. Le texte de remplacement est remplacement. Il est facultatif (dans ce cas, c'est le texte vide). À chaque fois que texte sera rencontré, il sera remplacé par remplacement.
Cette commande servira à définir les constantes.
VRAI sera remplacé systématiquement par 1 et FAUX par 0 dans la suite du texte.
Le préprocesseur définit un certain nombre de chaînes de remplacement automatiquement. Ce sont les suivantes :
__LINE__ : donne le numéro de la ligne courante ;
__FILE__ : donne le nom du fichier courant ;
__DATE__ : renvoie la date du traitement du fichier par le préprocesseur ;
__TIME__ : renvoie l'heure du trautement du fichier par le préprocesseur ;
__cplusplus : définie uniquement dans le cas d'une compilation C++. Sa valeur doit être 199711L pour les compilateurs compatibles avec le projet de norme du 2 décembre 1996. En pratique, sa valeur est dépendante de l'implémentation utilisée, mais on pourra utiliser cette chaîne de remplacement pour distinguer les parties de code écrites en C++ de celles écrites en C.
Note : Si __FILE__, __DATE__, __TIME__ et __cplusplus sont bien des constantes pour un fichier donné, ce n'est pas le cas de __LINE__. En effet, cette dernière « constante » change bien évidemment de valeur à chaque ligne. On peut considérer qu'elle est redéfinie automatiquement par le préprocesseur à chaque début de ligne.
On fera par ailleurs une distinction bien nette entre les constantes littérales définies avec la directive #define du préprocesseur et les constantes définies avec le mot-clé const. En effet, les constantes littérales ne réservent pas de mémoire. Ce sont des valeurs immédiates, définies par le compilateur. En revanche, les variables de classe de stockage const ont malgré tout une place mémoire réservée. Il est possible, par un transtypage de pointeur, de modifier leur valeur (opération déconseillée et de surcroît certainement inutile), et elles peuvent être modifiées par l'environnement si elles sont de type volatile. Ce sont donc des variables accessibles en lecture seule plutôt que des constantes. On ne pourra jamais supposer qu'une variable ne change pas de valeur sous prétexte qu'elle a la classe de stockage const, alors qu'évidemment, une vraie constante déclarée avec la directive #define du préprocesseur conservera toujours sa valeur (pourvu qu'on ne la redéfinisse pas).
Il est possible de déclarer un identificateur. Pour cela, on utilise aussi #define :
#define identificateur
Pour détruire l'identificateur, il faut utiliser #undef :
#undef identificateur
Lorsqu'un identificateur est défini, il est possible de faire des tests dessus (voir section suivante).
Syntaxe :
#ifdef identificateur ⋮ #endif
Le texte compris entre le #ifdef (c'est-à-dire « if defined ») et le #endif est laissé tel quel si l'identificateur identificateur est connu du préprocesseur. Sinon, il est supprimé. L'identificateur peut être déclaré en utilisant simplement la commande #define vue ci-dessus.
Il existe d'autres commandes conditionnelles :
#ifndef (if not defined ...) #elif (sinon, si ... ) #if (si ... )qui permettent de faire des fichiers dont certaines parties ne seront pas compilées. C'est ce qu'on appelle la compilation conditionnelle. La directive #if attend en paramètre une expression constante. Le texte qui la suit est inclus dans le fichier si et seulement si cette expression est non nulle. Par exemple : permet d'inclure un morceau de code C++ strictement à la norme décrite dans le projet de norme du 2 décembre 1996.
Une autre application courante des directives de compilation est la suivante :
#ifndef DejaLa #define DejaLa Texte à n'inclure qu'une seule fois au plus. #endifqui permet d'éviter que le texte soit inclus plusieurs fois, à la suite de plusieurs appels de #include. En effet, au premier appel, DejaLa n'est pas connu du préprocesseur. Il est donc déclaré et le texte est inclus. Lors de tout autre appel ultérieur, DejaLa existe, et le texte est n'est pas inclus. Ce genre d'écriture se rencontre dans les fichiers d'en-tête, pour lesquels en général on ne veut pas qu'une inclusion multiple ait lieu.
Le préprocesseur est capable d'effectuer d'autres actions que l'inclusion et la suppression de texte. Les directives qui permettent d'effectuer ces actions sont indiquées ci-dessous :
# : ne fait rien (directive nulle) ;
#error message : permet de stopper la compilation en affichant le message d'erreur donné en paramètre ;
#line numéro [fichier] : permet de changer le numéro de ligne courant et le nom du fichier courant lors de la compilation ;
#pragma texte : permet de donner des ordres dépendant de l'implémentation au compilateur. Toute implémentation qui ne reconnaît pas un ordre donné dans une directive #pragma doit l'ignorer pour éviter des messages d'erreurs.
| Précédent | Sommaire | Suivant |
| Le préprocesseur C | Niveau supérieur | Les macros |