Conditional inclusion
El preprocesador admite la compilación condicional de partes del archivo fuente. Este comportamiento se controla mediante las directivas
#if
,
#else
,
#elif
,
#ifdef
,
#ifndef
,
#elifdef
,
#elifndef
(desde C++23)
, y
#endif
.
Contenidos |
Sintaxis
#if
expresión
|
|||||||||
#ifdef
identificador
|
|||||||||
#ifndef
identificador
|
|||||||||
#elif
expresión
|
|||||||||
#elifdef
identificador
|
(desde C++23) | ||||||||
#elifndef
identificador
|
(desde C++23) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
Explicación
El bloque de preprocesamiento condicional comienza con
#if
,
#ifdef
o
#ifndef
, luego opcionalmente incluye cualquier número de directivas
#elif
,
#elifdef
, o
#elifndef
(desde C++23)
, luego opcionalmente incluye como máximo una directiva
#else
y finaliza con la directiva
#endif
. Cualquier bloque de preprocesamiento condicional interno se procesa por separado.
Cada una de las directivas
#if
,
#ifdef
,
#ifndef
,
#elif
,
#elifdef
,
#elifndef
(desde C++23)
, y
#else
controla el bloque de código hasta la primera directiva
#elif
,
#elifdef
,
#elifndef
(desde C++23)
,
#else
,
#endif
que no pertenezca a ningún bloque de preprocesamiento condicional interno.
#if
,
#ifdef
y
#ifndef
evalúan la condición especificada (ver abajo) y si resulta verdadera, compilan el bloque de código controlado. En ese caso, las directivas posteriores
#else
,
#elifdef
,
#elifndef
,
(desde C++23)
y
#elif
se ignoran. De lo contrario, si la condición especificada evalúa como falsa, se omite el bloque de código controlado y se procesa la directiva posterior
#else
,
#elifdef
,
#elifndef
,
(desde C++23)
o
#elif
(si existe). Si la directiva posterior es
#else
, el bloque de código controlado por la directiva
#else
se compila incondicionalmente. De lo contrario, la directiva
#elif
,
#elifdef
, o
#elifndef
(desde C++23)
actúa como si fuera una directiva
#if
: verifica la condición, compila u omite el bloque de código controlado según el resultado, y en este último caso procesa las directivas posteriores
#elif
,
#elifdef
,
#elifndef
,
(desde C++23)
y
#else
. El bloque de preprocesamiento condicional finaliza con la directiva
#endif
.
Evaluación de condiciones
#if, #elif
expresión
puede contener operadores unarios en forma de
defined
identificador
o
defined (
identificador
)
. El resultado es
1
si el
identificador
fue
definido como nombre de macro
, de lo contrario el resultado es
0
.
|
expression también puede contener las siguientes expresiones:
Los identificadores mencionados anteriormente se tratan como si fueran los nombres de macros definidas en este contexto. |
(since C++17) |
Después de toda la expansión de macros y evaluación de
defined
y las expresiones descritas anteriormente, cualquier identificador que no sea un
literal booleano
es reemplazado con el número
0
(esto incluye identificadores que son léxicamente palabras clave, pero no tokens alternativos como
and
).
Entonces la expresión se evalúa como una integral constant expression .
Si la expresión evalúa a un valor distinto de cero, el bloque de código controlado se incluye y se omite en caso contrario.
Nota: Hasta la resolución de
CWG issue 1955
,
#if
cond1
...
#elif
cond2
es diferente de
#if
cond1
...
#else
seguido por
#if
cond2
porque si
cond1
es verdadero, el segundo
#if
se omite y
cond2
no necesita estar bien formado, mientras que
#elif
's
cond2
debe ser una expresión válida. A partir de CWG 1955,
#elif
que conduce al bloque de código omitido también se omite.
Directivas combinadas
Comprueba si el identificador fue definido como un nombre de macro .
#ifdef
identifier
es esencialmente equivalente a
#if defined
identifier
.
#ifndef
identifier
es esencialmente equivalente a
#if !defined
identifier
.
|
|
(desde C++23) |
Notas
Mientras que las directivas
#elifdef
y
#elifndef
están destinadas para C++23, se recomienda a las implementaciones que las retroporten a los modos de lenguaje anteriores como extensiones conformes.
Ejemplo
#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 // Nota: si un compilador no soporta las directivas #elifdef/#elifndef de C++23 // entonces se seleccionará el bloque "inesperado" (ver abajo). #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // bloque esperado #else std::cout << "4: no!\n"; // selecciona inesperadamente este bloque saltando // directivas desconocidas y "saltando" directamente // desde "#ifdef CPU" a este bloque "#else" #endif // Para solucionar el problema anterior podemos definir condicionalmente la // macro ELIFDEF_SUPPORTED solo si se soportan las directivas #elifdef/#elifndef de C++23. #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"; // bloque esperado #else std::cout << "4: no3\n"; #endif #else // cuando #elifdef no está soportado, usar el antiguo y verboso "#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"; // bloque esperado #else std::cout << "4: no3\n"; #endif #endif }
Salida posible:
1: yes 2: yes 3: yes 4: no! 4: yes
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 1955 | C++98 | se requería que la expresión de #elif fuera válida | se omite el #elif fallido |
Véase también
|
Documentación de C
para
Inclusión condicional
|