Compilación condicional de código
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 odefined (
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 !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
|