directives #if, #elif, #else et #endif (C/C++)
La directive #if , avec les directives #elif, #else et #endif , contrôle la compilation des parties d’un fichier source. Si l’expression que vous écrivez (après la #if) a une valeur différente de zéro, le groupe de lignes qui suit immédiatement la directive #if est conservé dans l’unité de traduction.
Grammaire
conditionnel :
if-part elif-partsoptelse-partoptendif-line
if-part :
if-line text
if-line :
expressionconstante #if
identificateur de #ifdef
identificateur de #ifndef
elif-parts :
elif-line text
elif-parts elif-line text
elif-line :
expressionconstante #elif
else-part :
else-line text
else-line :
#else
endif-line :
#endif
Remarques
Chaque directive #if dans un fichier source doit être mise en correspondance par une directive #endif fermante. Un nombre quelconque de directives #elif peut apparaître entre les directives #if et #endif , mais au plus une directive #else est autorisée. La directive #else , si elle est présente, doit être la dernière directive avant #endif.
Les directives #if, #elif, #else et #endif peuvent s’imbriquer dans les parties de texte d’autres directives #if . Chaque directive #else, #elif ou #endif imbriquée appartient à la directive #if la plus proche.
Toutes les directives de compilation conditionnelle, telles que #if et #ifdef, doivent correspondre à une directive de #endif de fermeture avant la fin du fichier. Sinon, un message d’erreur est généré. Lorsque les directives de compilation conditionnelle sont contenues dans les fichiers Include, elles doivent satisfaire aux mêmes conditions : il ne doit y avoir aucune directive de compilation conditionnelle sans correspondance à la fin du fichier Include.
Le remplacement de macro est effectué dans la partie de la ligne qui suit une commande #elif , de sorte qu’un appel de macro peut être utilisé dans l’expression constante.
Le préprocesseur sélectionne l’une des occurrences de texte données pour un traitement ultérieur. Un bloc spécifié dans le texte peut être n’importe quelle séquence de texte. Il peut occuper plusieurs lignes. En règle générale, le texte est un texte de programme qui a une signification pour le compilateur ou le préprocesseur.
Le préprocesseur traite le texte sélectionné et le transmet au compilateur. Si le texte contient des directives de préprocesseur, le préprocesseur exécute ces directives. Seuls les blocs de texte sélectionnés par le préprocesseur sont compilés.
Le préprocesseur sélectionne un seul élément de texte en évaluant l’expression constante suivant chaque directive #if ou #elif jusqu’à ce qu’il trouve une expression constante vraie (différente de zéro). Il sélectionne tout le texte (y compris les autres directives de préprocesseur commençant par #) jusqu’à son #elif, #else ou #endif associé.
Si toutes les occurrences d’expression constante sont false, ou si aucune directive #elif n’apparaît , le préprocesseur sélectionne le bloc de texte après la clause #else . Lorsqu’il n’existe aucune clause #else et que toutes les instances d’expression constante dans le bloc #if ont la valeur false, aucun bloc de texte n’est sélectionné.
Constant-expression est une expression constante entière avec ces restrictions supplémentaires :
Les expressions doivent avoir un type intégral et peuvent inclure uniquement des constantes entières, des constantes de caractères et l’opérateur défini .
L’expression ne peut pas utiliser
sizeof
ou un opérateur de conversion de type.L’environnement cible peut ne pas être en mesure de représenter toutes les plages d’entiers.
La traduction représente le type
int
de la même façon que le typelong
etunsigned int
de la même façon queunsigned long
.Le traducteur peut traduire les constantes caractère en un ensemble de valeurs de code différentes de l'ensemble de l'environnement cible. Pour déterminer les propriétés de l’environnement cible, utilisez une application créée pour cet environnement afin de vérifier les valeurs des LIMITES. Macros H .
L’expression ne doit pas interroger l’environnement et doit rester isolée des détails de l’implémentation sur l’ordinateur cible.
Opérateurs de préprocesseur
défini
L’opérateur de préprocesseur défini peut être utilisé dans des expressions constantes spéciales, comme le montre la syntaxe suivante :
defined(identifier)
identificateurdéfini
Cette expression constante est considérée comme true (différente de zéro) si l’identificateur est actuellement défini. Sinon, la condition n'est pas vérifiée (0). Un identificateur défini comme du texte vide est considéré comme défini. L’opérateur défini peut être utilisé dans un #if et une directive #elif , mais nulle part ailleurs.
Dans l’exemple suivant, les directives #if et #endif contrôlent la compilation de l’un des trois appels de fonction :
#if defined(CREDIT)
credit();
#elif defined(DEBIT)
debit();
#else
printerror();
#endif
L'appel de fonction à credit
est compilé si l'identificateur CREDIT
est défini. Si l'identificateur DEBIT
est défini, l'appel de fonction à debit
est compilé. Si aucun de ces deux identificateurs n'est défini, l'appel de printerror
est compilé. credit
Et CREDIT
sont des identificateurs distincts en C et C++, car leurs cas sont différents.
Les instructions de compilation conditionnelle dans l'exemple suivant supposent une constante symbolique définie au préalable et nommée DLEVEL
.
#if DLEVEL > 5
#define SIGNAL 1
#if STACKUSE == 1
#define STACK 200
#else
#define STACK 100
#endif
#else
#define SIGNAL 0
#if STACKUSE == 1
#define STACK 100
#else
#define STACK 50
#endif
#endif
#if DLEVEL == 0
#define STACK 0
#elif DLEVEL == 1
#define STACK 100
#elif DLEVEL > 5
display( debugptr );
#else
#define STACK 200
#endif
Le premier bloc #if affiche deux ensembles de directives #if imbriquées, #else et #endif . Le premier jeu de directives est traité uniquement si DLEVEL > 5
a la valeur true. Sinon, les instructions après #else sont traitées.
Les directives #elif et #else dans le deuxième exemple sont utilisées pour effectuer l’un des quatre choix, en fonction de la valeur de DLEVEL
. La constante STACK
a la valeur 0, 100 ou 200, selon la définition de DLEVEL
. Si DLEVEL
est supérieur à 5, l'instruction
#elif DLEVEL > 5
display(debugptr);
est compilé et STACK
n’est pas défini.
Une utilisation courante de la compilation conditionnelle consiste à empêcher plusieurs inclusions du même fichier d'en-tête. En C++, où les classes sont souvent définies dans les fichiers d’en-tête, des constructions comme celle-ci peuvent être utilisées pour empêcher plusieurs définitions :
/* EXAMPLE.H - Example header file */
#if !defined( EXAMPLE_H )
#define EXAMPLE_H
class Example
{
//...
};
#endif // !defined( EXAMPLE_H )
Le code précédent vérifie si la constante symbolique EXAMPLE_H
est définie. Si c’est le cas, le fichier a déjà été inclus et ne nécessite pas de retraitement. Sinon, la constante EXAMPLE_H
est définie pour marquer EXAMPLE.H comme déjà traité.
__has_include
Visual Studio 2017 version 15.3 et ultérieures : détermine si un en-tête de bibliothèque est disponible pour inclusion :
#ifdef __has_include
# if __has_include(<filesystem>)
# include <filesystem>
# define have_filesystem 1
# elif __has_include(<experimental/filesystem>)
# include <experimental/filesystem>
# define have_filesystem 1
# define experimental_filesystem
# else
# define have_filesystem 0
# endif
#endif