Les mécanismes de compilation conditionnelles ont pour but de compiler
ou d'ignorer des ensembles de lignes, le choix étant basé sur un test
exécuté à la compilation.
Quand le préprocesseur rencontre :
#ifexpression ensemble-de-lignes #endif
il évalue expression.
Si expression délivre une valeur non nulle, ensemble-de-lignes
est compilé, sinon ensemble-de-lignes est ignoré.
L'évaluation de expression à lieu au moment de la compilation,
elle ne doit donc comporter que des constantes.
L'ensemble-de-lignes est une suite de lignes quelconques.
Sur rencontre de :
#ifexpression ensemble-de-lignes1 #else ensemble-de-lignes2 #endif
le préprocesseur évalue expression.
Si expression délivre une valeur non nulle,
ensemble-de-lignes1 est compilé
et ensemble-de-lignes2 est ignoré, sinon
ensemble-de-lignes1 est ignoré
et ensemble-de-lignes2 est compilé.
De manière à imbriquer aisément des #if dans des #if, il existe
une commande #elif dont la sémantique est else if.
Elle s'utilise de la manière suivante :
#ifexpression1 ensemble-de-lignes1 #elifexpression2 ensemble-de-lignes2
...
#elifexpressionn ensemble-de-lignesn #else ensemble-de-ligneselse #endif
Un seul ensemble-de-lignes sera compilé : celui correspondant à la
première expressioni qui s'évaluera à une valeur non nulle si
elle existe, ou bien ensemble-de-ligneselse
si toutes les expressioni s'évaluent à 0.
Dans ce qui précède il est possible de remplacer les commandes #ifexpression par :
#ifdefnom ou
#ifndefnom ou
Dans ce cas, le test ne porte plus sur la nullité ou non d'une expression, mais
sur la définition ou non d'une macro.
La commande #ifdefnom a pour sémantique :
<< si nom est défini >>, et #ifndefnom
a pour sémantique : << si nom n'est pas défini >>.
L'opérateur defined est un opérateur spécial : il ne peut être
utilisé que dans le contexte d'une commande #if ou #elif.
Il peut être utilisé sous l'une des deux formes suivantes : definednom ou bien : defined (nom).
Il délivre la valeur 1 si nom est une macro définie, et la valeur 0
sinon.
L'intérêt de cet opérateur est de permettre d'écrire des tests portant
sur la définition de plusieurs macros, alors que #ifdef ne peut en
tester qu'une.
La commande #error a la syntaxe suivante :
#errorsuite-d-unités-lexicales
La rencontre de cette commande provoquera l'émission d'un message d'erreur
comprenant la suite-d-unités-lexicales.
Cette commande a pour utilité de capturer à la compilation des conditions
qui font que le programme ne peut pas s'exécuter sur cette plate-forme.
Voici un exemple où on teste que la taille des entiers est suffisante :
#include <limits.h>
#if INT_MAX < 1000000
#error "Entiers trop petits sur cette machine"
#endif
La compilation conditionnelle a pour but essentiel d'adapter le programme
à son environnement d'exécution : soit il s'agit d'un programme système
devant s'adapter au matériel sur lequel il s'exécute, soit il s'agit d'un
programme d'application qui doit s'adapter au système sur lequel il s'exécute.
Prenons par exemple le système UNIX qui existe en deux grandes
variantes : la variante BSD et la variante SYSTEM V.
La routine de recherche d'un caractère déterminé dans une chaîne s'appelle
index en BSD et strchr en SYSTEM V, mais l'interface
est le même.
Voici comment on peut écrire un programme se compilant et s'exécutant sur les
deux plate-formes : le programmeur peut décider d'utiliser un nom à lui,
par exemple RechercheCar, et de le définir comme ci-dessous.
#if defined(HAS_INDEX)
#define RechercheCar index
#elif defined(HAS_STRCHR)
#define RechercheCar strchr
#else
#error "Impossible de réaliser RechercheCar"
#endif