Namespaces
Variants

Conditional inclusion

From cppreference.net

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 C23) , et #endif .

Table des matières

Syntaxe

#if expression
#ifdef identifiant
#ifndef identifiant
#elif expression
#elifdef identifiant (depuis C23)
#elifndef identifiant (depuis C23)
#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 C23) , inclut optionnellement au plus une directive #else et se termine par la directive #endif . Tout bloc de prétraitement conditionnel interne est traité séparément.

Chacune des directives #if , #ifdef , #ifndef , #elif , #elifdef , #elifndef (depuis C23) , et #else contrôle un bloc de code jusqu'à la première directive #elif , #elifdef , #elifndef (depuis C23) , #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 à vrai, compilent le bloc de code contrôlé. Dans ce cas, les directives suivantes #else , #elifdef , #elifndef , (depuis C23) et #elif sont ignorées. Sinon, si la condition spécifiée est évaluée à faux, le bloc de code contrôlé est ignoré et la directive suivante #else , #elifdef , #elifndef , (depuis C23) ou #elif (le cas échéant) 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 C23) agit comme s'il s'agissait d'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 C23) et #else . Le bloc de prétraitement conditionnel est terminé par la directive #endif .

Évaluation conditionnelle

#if, #elif

L' expression est une expression constante, utilisant uniquement des constantes et des identifiants, définis à l'aide de la directive #define . Tout identifiant, qui n'est pas littéral, non défini à l'aide de la directive #define , s'évalue à 0 sauf true qui s'évalue à 1 (depuis C23) .

L'expression peut contenir des opérateurs unaires sous la forme defined identifiant ou defined ( identifiant ) qui renvoient 1 si l' identifiant a été défini en utilisant la directive #define et 0 sinon. Dans ce contexte, __has_include , __has_embed et __has_c_attribute sont traités comme s'ils étaient des noms de macros définies. (depuis C23) Si l' expression s'évalue à une valeur non nulle, le bloc de code contrôlé est inclus et ignoré sinon. Si un identifiant utilisé n'est pas une constante, il est remplacé par 0 .

Dans le contexte d'une directive de préprocesseur, une expression __has_c_attribute détecte si un jeton d'attribut donné est pris en charge et sa version supportée. Voir Test d'attributs .

(depuis C23)

Note : Jusqu'à DR 412 , #if cond1 ... #elif cond2 diffère de #if cond1 ... #else suivi de #if cond3 car si cond1 est vrai, le second #if est ignoré et cond3 n'a pas besoin d'être bien formé, tandis que #elif nécessite que cond2 soit une expression valide. Depuis DR 412 , #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 C23)

Notes

Bien que #elifdef et #elifndef ciblent C23, les implémentations peuvent les rétroporter vers les modes de langage plus anciens en tant qu'extensions conformes.

Exemple

#define ABCD 2
#include <stdio.h>
int main(void)
{
#ifdef ABCD
    printf("1: yes\n");
#else
    printf("1: no\n");
#endif
#ifndef ABCD
    printf("2: no1\n");
#elif ABCD == 2
    printf("2: yes\n");
#else
    printf("2: no2\n");
#endif
#if !defined(DCBA) && (ABCD < 2 * 4 - 3)
    printf("3: yes\n");
#endif
// C23 directives #elifdef/#elifndef
#ifdef CPU
    printf("4: no1\n");
#elifdef GPU
    printf("4: no2\n");
#elifndef RAM
    printf("4: yes\n"); // sélectionné en mode C23, peut être sélectionné en mode pré-C23
#else
    printf("4: no3\n"); // peut être sélectionné en mode pré-C23
#endif
}

Sortie possible :

1: yes
2: yes
3: yes
4: yes

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C publiées antérieurement.

DR Appliqué à Comportement publié Comportement corrigé
DR 412 C89 l'expression d'un #elif échoué devait être valide un #elif échoué est ignoré

Références

  • Norme C23 (ISO/CEI 9899:2024) :
  • 6.10.1 Inclusion conditionnelle (p: À DÉTERMINER)
  • Norme C17 (ISO/CEI 9899:2018):
  • 6.10.1 Inclusion conditionnelle (p: 118-119)
  • Norme C11 (ISO/CEI 9899:2011) :
  • 6.10.1 Inclusion conditionnelle (p: 162-164)
  • Norme C99 (ISO/IEC 9899:1999) :
  • 6.10.1 Inclusion conditionnelle (p: 147-149)
  • Norme C89/C90 (ISO/IEC 9899:1990) :
  • 3.8.1 Inclusion conditionnelle

Voir aussi

Documentation C++ pour Inclusion conditionnelle