Namespaces
Variants

Conditional inclusion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Preprocessor
#if #ifdef #ifndef #else #elif #elifdef #elifndef #endif
(C++23) (C++23)
(C++26)

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 :

  • __has_include expressions, qui détectent si un fichier d'en-tête ou source existe.
  • __has_cpp_attribute expressions, qui détectent si un jeton d'attribut donné est pris en charge et sa version supportée.
(depuis C++20)
  • __has_embed expressions, qui détectent si une ressource est disponible pour être intégrée.
(depuis C++26)

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 .

#elifdef identifier est essentiellement équivalent à #elif defined identifier .

#elifndef identifier est essentiellement équivalent à #elif !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