Conditional inclusion
Le préprocesseur prend en charge la compilation conditionnelle de parties du fichier source. Ce comportement est contrôlé par les directives
#if
,
#else
,
#elif
,
#ifdef
,
#ifndef
,
#elifdef
,
#elifndef
(depuis C++23)
, et
#endif
.
Table des matières |
Syntaxe
#if
expression
|
|||||||||
#ifdef
identifiant
|
|||||||||
#ifndef
identifiant
|
|||||||||
#elif
expression
|
|||||||||
#elifdef
identifiant
|
(depuis C++23) | ||||||||
#elifndef
identifiant
|
(depuis C++23) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
Explication
Le bloc de prétraitement conditionnel commence par la directive
#if
,
#ifdef
ou
#ifndef
, inclut ensuite optionnellement un nombre quelconque de directives
#elif
,
#elifdef
, ou
#elifndef
(depuis C++23)
, inclut optionnellement au plus une directive
#else
et se termine par la directive
#endif
. Tous les blocs de prétraitement conditionnels internes sont traités séparément.
Chacune des directives
#if
,
#ifdef
,
#ifndef
,
#elif
,
#elifdef
,
#elifndef
(depuis C++23)
, et
#else
contrôle le bloc de code jusqu'à la première directive
#elif
,
#elifdef
,
#elifndef
(depuis C++23)
,
#else
,
#endif
n'appartenant à aucun bloc de prétraitement conditionnel interne.
#if
,
#ifdef
et
#ifndef
testent la condition spécifiée (voir ci-dessous) et si elle est évaluée à true, compilent le bloc de code contrôlé. Dans ce cas, les directives suivantes
#else
,
#elifdef
,
#elifndef
,
(depuis C++23)
et
#elif
sont ignorées. Sinon, si la condition spécifiée est évaluée à false, le bloc de code contrôlé est ignoré et la directive suivante
#else
,
#elifdef
,
#elifndef
,
(depuis C++23)
ou
#elif
(si présente) est traitée. Si la directive suivante est
#else
, le bloc de code contrôlé par la directive
#else
est compilé inconditionnellement. Sinon, la directive
#elif
,
#elifdef
, ou
#elifndef
(depuis C++23)
agit comme si elle était une directive
#if
: vérifie la condition, compile ou ignore le bloc de code contrôlé en fonction du résultat, et dans ce dernier cas traite les directives suivantes
#elif
,
#elifdef
,
#elifndef
,
(depuis C++23)
et
#else
. Le bloc de prétraitement conditionnel est terminé par la directive
#endif
.
Évaluation de condition
#if, #elif
expression
peut contenir des opérateurs unaires sous la forme
defined
identifiant
ou
defined (
identifiant
)
. Le résultat est
1
si l'
identifiant
a été
défini comme un nom de macro
, sinon le résultat est
0
.
|
expression peut également contenir les expressions suivantes :
Les identifiants mentionnés ci-dessus sont traités comme s'ils étaient les noms de macros définies dans ce contexte. |
(depuis C++17) |
Après toute expansion de macro et évaluation de
defined
et des expressions décrites ci-dessus, tout identifiant qui n'est pas un
littéral booléen
est remplacé par le nombre
0
(cela inclut les identifiants qui sont lexicalement des mots-clés, mais pas les jetons alternatifs comme
and
).
L'expression est alors évaluée comme une integral constant expression .
Si l' expression évalue à une valeur non nulle, le bloc de code contrôlé est inclus et ignoré dans le cas contraire.
Note : Jusqu'à la résolution de
CWG issue 1955
,
#if
cond1
...
#elif
cond2
diffère de
#if
cond1
...
#else
suivi de
#if
cond2
car si
cond1
est vrai, le second
#if
est ignoré et
cond2
n'a pas besoin d'être bien formé, tandis que
#elif
nécessite que
cond2
soit une expression valide. Depuis CWG 1955,
#elif
qui précède un bloc de code ignoré est également ignoré.
Directives combinées
Vérifie si l'identificateur a été défini comme nom de macro .
#ifdef
identifier
est essentiellement équivalent à
#if defined
identifier
.
#ifndef
identifier
est essentiellement équivalent à
#if !defined
identifier
.
|
|
(depuis C++23) |
Notes
Bien que
#elifdef
et
#elifndef
visent C++23, les implémentations sont encouragées à les rétroporter vers les modes de langage antérieurs en tant qu'extensions conformes.
Exemple
#define ABCD 2 #include <iostream> int main() { #ifdef ABCD std::cout << "1: yes\n"; #else std::cout << "1: no\n"; #endif #ifndef ABCD std::cout << "2: no1\n"; #elif ABCD == 2 std::cout << "2: yes\n"; #else std::cout << "2: no2\n"; #endif #if !defined(DCBA) && (ABCD < 2*4-3) std::cout << "3: yes\n"; #endif // Notez que si un compilateur ne prend pas en charge les directives #elifdef/#elifndef de C++23 // alors le bloc "inattendu" (voir ci-dessous) sera sélectionné. #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // bloc attendu #else std::cout << "4: no!\n"; // sélectionne inopinément ce bloc en ignorant // les directives inconnues et en "sautant" directement // de "#ifdef CPU" à ce bloc "#else" #endif // Pour résoudre le problème ci-dessus, nous pouvons définir conditionnellement // la macro ELIFDEF_SUPPORTED uniquement si les directives C++23 // #elifdef/#elifndef sont prises en charge. #if 0 #elifndef UNDEFINED_MACRO #define ELIFDEF_SUPPORTED #else #endif #ifdef ELIFDEF_SUPPORTED #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // bloc attendu #else std::cout << "4: no3\n"; #endif #else // lorsque #elifdef n'est pas pris en charge, utiliser l'ancienne syntaxe verbeuse "#elif defined" #ifdef CPU std::cout << "4: no1\n"; #elif defined GPU std::cout << "4: no2\n"; #elif !defined RAM std::cout << "4: yes\n"; // bloc attendu #else std::cout << "4: no3\n"; #endif #endif }
Sortie possible :
1: yes 2: yes 3: yes 4: no! 4: yes
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 1955 | C++98 | l'expression du #elif devait être valide | le #elif est ignoré |
Voir aussi
|
Documentation C
pour
Inclusion conditionnelle
|