Espacios de nombres
Variantes
Acciones

Compilación condicional de código

De cppreference.com
 
 
Lenguaje C++
Temas generales
Control de flujo
Instrucciones de ejecución condicionales
Instrucciones de iteración (bucles)
Declaraciones de salto
Funciones
Declaración de funciones
Declaración de funciones lambda
Especificador inline
Especificación de excepciones (hasta C++20)
Especificador noexcept (C++11)
Excepciones
Espacios de nombres
Tipos
Especificadores
decltype (C++11)
auto (C++11)
alignas (C++11)
Especificadores de duración de almacenamiento
Inicialización
Expresiones
Representaciones alternas
Literales
Booleanos - Enteros - De punto flotante
De carácter - De cadena - nullptr (C++11)
Definidos por el usuario (C++11)
Utilidades
Atributos (C++11)
Tipos
Declaración de typedef
Declaración de alias de tipo (C++11)
Conversiones
Conversiones implícitas - Conversiones explícitas
static_cast - dynamic_cast
const_cast - reinterpret_cast
Asignación de memoria
Clases
Propiedades de funciones específicas de la clase
Funciones miembro especiales
Plantillas
Misceláneos
 
 

El preprocesador permite la compilación condicional de algunas partes del archivo fuente. Este comportamiento está controlado por las directivas #if, #else, #elif, #ifdef, #ifndef, #elifdef, #elifndef (desde C++23) y #endif.

Contenido

[editar] Sintaxis

#if expresión
#elif expresión
#ifdef identificador
#ifndef identificador
#elifdef identificador (desde C++23)
#elifndef identificador (desde C++23)
#else
#endif

[editar] Explicación

Un bloque de preprocesamiento condicional comienza con la directiva #if, #ifdef o #ifndef, después, opcionalmente, se puede incluir cualquier número de directivas #elif, #elifdef, or #elifndef (desde C++23), a continuación, opcionalmente, se incluye como mucho una directiva #else y se termina con la directiva de cierre #endif. Todos los bloques de preprocesamiento condicional interiores se procesan por separado .

Cada una de las directivas #if, #elif, #elifdef, #elifndef (desde C++23), #else, #ifdef y #ifndef abarca el bloque de código hasta la primera directiva #elif, #elifdef, #elifndef (desde C++23), #else o #endif que no pertenece a ningún bloque interno de preprocesamiento condicional.

Las directivas #if, #ifdef y #ifndef comprueban la condición especificada (ver más abajo) y si se evalúa como verdadera, compila el bloque de código abarcado. En ese caso, se ignoran las siguientes directivas #else, #elifdef, #elifndef, (desde C++23) y #elif. De lo contrario, si la condición especificada se evalúa como falsa, el bloque de código abarcado se omite y la siguiente directiva #else, #elifdef, #elifndef, (desde C++23) o #elif (si las hay) se procesa. Si la directiva siguiente es #else, el bloque de código abarcado por la directiva #else se compila incondicionalmente. En otro caso, la directiva #elif, #elifdef, or #elifndef (desde C++23) actúa como si se tratara de directiva #if: verifica que se cumpla la condición, compila u omite el bloque de código abarcado en función del resultado, y en el caso de omisión, se procesa las siguientes directivas #elif, #elifdef, #elifndef, (desde C++23) y #else. El bloque de preprocesamiento condicional se finaliza con la directiva #endif.

[editar] Evaluación de condición

[editar] #if, #elif

La expression, es una expresión constante.

La expresión puede contener:

  • operadores unarios de la forma defined identificador o defined (identificador). El resultado es 1 si el identificador estaba definido como un nombre de macro, de lo contrario el resultado es 0.
  • (desde C++17) las expresiones __has_include, que detecta si existe un archivo de cabecera o fuente.
  • (desde C++20) las expresiones __has_cpp_attribute, que detecta si se admite un token de atributo determinado y su versión compatible.

Después de la expansión de todas las macros y la evaluación de las expresiones defined , __has_include (desde C++17), and __has_cpp_attribute (desde C++20), cualquier identificadro que no es un literal booleano se sustituye por el número 0 (esto incluye identificadores que son lexicamente palabras clave, pero no los tokenes de alternativa como and).

Luego se evalúa la expresión como una expresión constante entera.

Si la expresión resulta en un valor no cero, se incluye el bloque de código que abarca, y se descarta en otro caso.

Nota: Hasta CWG 1955, #if cond1 ... #elif cond2 es diferente de #if cond1 ... #else seguido de #if cond2 debido a que si cond1 es verdadero, se descarta el segundo #if y cond2 no necesita estar bien fromada, mientras que la while cond2 de #elif debe ser una expresión válida. A partir de CWG 1955, el #elif que lleva el bloque código omitido también se omite.

[editar] Directivas combinadas

Comprueba si el identificador se definió como un nombre de macro.

#ifdef identificador es equivalente a #if defined identificador.

#ifndef identificador es equivalente a #if !definedidentificador.

#elifdef identificador es equivalente a #elif defined identificador.

#elifndef identificador es equivalente a #elif !defined identificador.

(desde C++23)

[editar] Notas

Mientras que las directivas #elifdef y #elifndef se dirigen a C++23, se recomienda a las implementaciones que las retro-porten a los modos de lenguaje más antiguos.

[editar] Ejemplo

#define ABCD 2
#include <iostream>
 
int main()
{
 
#ifdef ABCD
    std::cout << "1: si\n";
#else
    std::cout << "1: no\n";
#endif
 
#ifndef ABCD
    std::cout << "2: no1\n";
#elif ABCD == 2
    std::cout << "2: si\n";
#else
    std::cout << "2: no2\n";
#endif
 
#if !defined(DCBA) && (ABCD < 2*4-3)
    std::cout << "3: si\n";
#endif
 
// Tenga en cuenta que si el compilador no soporta las directivas #elifdef/#elifndef  
// de C++23 entonces se selecciona el bloque "inesperado" (ver más abajo).
#ifdef CPU
    std::cout << "4: no1\n";
#elifdef GPU
    std::cout << "4: no2\n";
#elifndef RAM
    std::cout << "4: si\n"; // bloque esperado
#else
    std::cout << "4: no!\n"; // selecciona inesperadamente este bloque omitiendo 
                             // directivas desconocidas y "saltando" directamente
                             // desde "#ifdef CPU" a este bloque "#else"
#endif
 
 
// Para solucionar el problema anterior,  podemos definir condicionalmente
// la macro ELIFDEF_SOPORTADO solo si las directivas #elifdef/#elifndef
//  de C++23 son soportadas.
#if 0
#elifndef MACRO_INDEFINIDA
#define ELIFDEF_SOPORTADO
#else
#endif
 
#ifdef ELIFDEF_SOPORTADO
    #ifdef CPU
        std::cout << "4: no1\n";
    #elifdef GPU
        std::cout << "4: no2\n";
    #elifndef RAM
        std::cout << "4: si\n"; // bloque esperado
    #else
        std::cout << "4: no3\n";
    #endif
#else // cunado no se soporta #elifdef se usa la versión antigua `#elif defined`
    #ifdef CPU
        std::cout << "4: no1\n";
    #elif defined GPU
        std::cout << "4: no2\n";
    #elif !defined RAM
        std::cout << "4: si\n"; // bloque esperado
    #else
        std::cout << "4: no3\n";
    #endif
#endif
}

Posible salida:

1: si
2: si
3: si
4: no!
4: si

[editar] Informes de defectos

Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
CWG 1955 C++98 Se requería que la expresión de #elif fallida fuera válida #elif fallido se omite

[editar] Véase también

Documentación de C para Compilación condicional de código