#if, #elif, #else et #endif, directives (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 l '#if) a une valeur différente de zéro, le groupe de lignes suivant immédiatement la directive #if est conservé dans l’unité de traduction.
Grammaire
conditionnel :
if-part elif-partsopt else-partopt endif-line
if-part :
texte if-line
if-line :
#if constante-expression
identificateur de #ifdef
identificateur de #ifndef
elif-parts :
texte elif-line
elif-parts elif-line text
elif-line :
expression constante #elif
else-part :
texte de ligne else
else-line :
#else
endif-line :
#endif
Notes
Chaque directive #if dans un fichier source doit être mise en correspondance par une directive de #endif fermante. N’importe quel nombre de directives #elif peuvent apparaître entre les directives #if et #endif , mais au plus une directive #else est autorisée. La directive #else , le cas échéant, doit être la dernière directive avant #endif.
Les directives #if, #elif, #else et #endif peuvent être imbriquées dans les parties texte d’autres directives #if. Chaque directive #else imbriquée, #elif ou #endif appartient à la directive #if la plus proche.
Toutes les directives de compilation conditionnelle, telles que #if et #ifdef, doivent correspondre à une directive de #endif fermante 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, afin qu’un appel de macro puisse ê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 qui suit chaque #if ou directive #elif jusqu’à ce qu’elle trouve une expression constante vraie (différente de zéro). Il sélectionne tout le texte (y compris d’autres directives de préprocesseur commençant #par ) jusqu’à son #elif associé, #else ou #endif.
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 sont false, aucun bloc de texte n’est sélectionné.
L’expression constante 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 cast de type.L’environnement cible peut ne pas 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 pour 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 illustré par la syntaxe suivante :
defined( identificateur )
identificateur défini
Cette expression constante est considérée comme vraie (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é. Les deux 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 n’a pas besoin 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érieure : 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