#ifdef, #ifndef, #if, #endif în C++

Operatori alternativi și preprocesor C++98 (#elifdef: C++23)

Compilare condiționată: păstrează sau elimină bucăți de cod înainte de compilare, după ce macro-uri sunt definite.

Sintaxă
#ifdef NUME
    ...
#elif conditie
    ...
#else
    ...
#endif
#ifndef NUME ... #endif
#if defined(NUME) && VALOARE > 2 ... #endif

Ce face #ifdef, #ifndef, #if, #endif

#ifdef NUME păstrează codul de până la #else sau #endif doar dacă macro-ul NUME este definit; altfel îl elimină complet, ca și cum nu ar fi fost scris. #ifndef face invers. #if evaluează o expresie cu numere întregi, iar defined(NUME) verifică existența unui macro.

Se folosește pentru: cod de depanare activat doar în versiunea de test, cod diferit pe sisteme diferite (_WIN32, __APPLE__, __linux__), verificarea standardului (__cplusplus) și gărzile de includere ale fișierelor antet.

Macro-urile pot fi definite și din linia de comandă: c++ -DDEBUG main.cpp echivalează cu #define DEBUG la începutul fișierului. C++23 a adăugat #elifdef și #elifndef.

Exemple

Exemplul 1: Mesaje de depanare activate cu DEBUG

Cu #define DEBUG, mesajul de depanare rămâne în program. Fără el (sau fără -DDEBUG), linia ar dispărea complet din codul compilat.

#include <print>

#define DEBUG

int main() {
    int total = 0;
    for (int i = 1; i <= 3; ++i) {
        total += i * 10;
#ifdef DEBUG
        std::println("[debug] pas {}, total {}", i, total);
#endif
    }
    std::println("Total: {}", total);
}

Rezultat

[debug] pas 1, total 10
[debug] pas 2, total 30
[debug] pas 3, total 60
Total: 60

Exemplul 2: Cod diferit după sistem

Programul a rulat pe macOS, unde compilatorul definește __APPLE__.

#include <print>

int main() {
#if defined(_WIN32)
    std::println("Rulez pe Windows");
#elif defined(__APPLE__)
    std::println("Rulez pe macOS");
#elif defined(__linux__)
    std::println("Rulez pe Linux");
#else
    std::println("Sistem necunoscut");
#endif

#if __cplusplus >= 202302L
    std::println("Compilat cu C++23 sau mai nou");
#endif
}

Rezultat

Rulez pe macOS
Compilat cu C++23 sau mai nou

Exemplul 3: #ifndef și #elifdef (C++23)

#include <print>

#define VERSIUNE_PRO

#ifndef LIMITA_UTILIZATORI
#define LIMITA_UTILIZATORI 5
#endif

int main() {
#ifdef VERSIUNE_GRATUITA
    std::println("Versiune gratuită");
#elifdef VERSIUNE_PRO
    std::println("Versiune Pro");
#endif
    std::println("Limită utilizatori: {}", LIMITA_UTILIZATORI);
}

Rezultat

Versiune Pro
Limită utilizatori: 5

Greșeli frecvente

  • Uiți #endif. Preprocesorul dă eroarea „unterminated conditional directive”, adesea la sfârșitul fișierului, departe de locul greșelii.
  • Scrii #ifdef DEBUG && VERBOSE. #ifdef acceptă un singur nume; pentru condiții compuse folosește #if defined(DEBUG) && defined(VERBOSE).
  • Folosești în #if variabile sau constexpr-uri din C++. Preprocesorul rulează înainte de compilare și știe doar de macro-uri și numere; pentru condiții pe valori C++ folosește if constexpr.

Comenzi înrudite

  • #define: Definește un macro: preprocesorul înlocuiește textual numele cu valoarea lui, peste tot în cod, înainte de compilare.
  • #include: Directivă a preprocesorului care copiază conținutul unui fișier antet în locul ei, ca să poți folosi funcțiile și clasele declarate acolo.
  • #pragma once: Pusă la începutul unui fișier antet, face ca fișierul să fie inclus o singură dată, chiar dacă apare în mai multe #include-uri.
  • if constexpr: Un if evaluat la compilare: ramura falsă este eliminată complet, deci poate conține cod care nu s-ar compila pentru tipul curent.