Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


Directivas  #if,  #elif,  #else,  #endif

§1  Sinopsis

C++ ofrece la posibilidad de compilación condicional mediante la inclusión de ciertas directivas que controlan el comportamiento del preprocesador, de forma que este puede ignorar o compilar determinadas líneas del código en función de ciertas condiciones que son evaluadas durante el preproceso.

§2  Sintaxis

#if k-expresion-1
   <seccion-1>
<#elif k-expresion-2
   <seccion-2>

 ...
 
<#elif k-expresion-n
   <seccion-n>
<#else
   <seccion-final>
#endif

§3  Comentario

Las directivas condicionales #if, #elif, #else  y #endif se comportan igual que las sentencias C/C++ de selección ( 4.10.2). Si k-expresion-1 -sujeta a posible macro-expansión- es cierta (distinto de cero), las líneas de código de seccion-1, que pueden estar vacías, ser líneas normales de código o incluso de preprocesado, son preprocesadas y pasadas al compilador. Si es falsa (cero), la seccion-1 es ignorada por completo.

En el caso de ser cierta, después que se ha procesado la seccion-1, el control pasa a la correspondiente #endif, con lo que se termina la sentencia condicional y se continúa con la sección siguiente. Si es falsa, el control pasa a la siguiente #elif, donde se evalúa k-expresion-2. Si es cierta, se procesa la seccion-2, tras lo cual el control pasa al correspondiente #endif. En caso contrario, si k-expresion-2 es falsa, el control pasa al siguiente #elif. Así sucesivamente hasta que se llega a algún #else o #endif (#else es opcional y se alcanza si todas las comprobaciones previas han sido falsas).

Las diferentes secciones pueden contener a su vez otras cláusulas condicionales anidadas en cualquier profundidad. Cada #if debe contar con su correspondiente #endif. Puede haber cualquier número de #elif, pero solo un #else (que debe ser el último).


§4  Las expresiones k-expresion-n deben evaluarse a una constante entera. Es decir, debe ser una expresión constante que se reduzca a un entero, aunque esta expresión puede tener ciertas restricciones ( 3.2.3a).

Ejemplo

#if SYSTEM == SYSV
    #define HDR "sysv.h"
#elif SYSTEM == BSD
    #define HDR "bsd.h"
#elif SYSTEM == MSDOS
    #define HDR "msdos.h"
#else
    #define HDR "default.h"
#endif
#include HDR            // incluir la cabecera adecuada.

En este caso, se supone que SYSV, BSD y MSDOS son constantes simbólicas que en algún punto están definidas como valores enteros. A su vez SYSTEM es igualmente una constante simbólica cuyo valor es un entero.


Nada impide que la expresión condicional sea a su vez una expresión compuesta, tal como se muestra en el siguiente ejemplo tomado de un caso real de programación Windows.

#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) ||  defined(__WXX11__)
    #include "mondrian.xpm"
#endif

En este caso los nombres en mayúsculas corresponden a constantes manifiestas ( 1.4.1a) definidas en distintos compiladores C++. Ver ejemplos adicionales en  4.9.10c y 1.4.


El ejemplo siguiente muestra unas sentencias de compilación condicional en función del valor de la constante simbólica DLEVEL que se supone ha sido definida previamente.

#if DLEVEL > 5
  #define SIGNAL 1
  #if STACKUSE == 1
    #define STACK 200
  #else
    #define STACK 100
  #endif
#else
  #define SIGNAL 0
  #if STACKUSE == 1
    #define STACK 100
  #else
    #define STACK 50
  #endif
#endif
#if DLEVEL == 0
  #define STACK 0
#elif DLEVEL == 1
  #define STACK 100
#elif DLEVEL > 5
  display( debugptr );
#else
  #define STACK 200
#endif

El primer bloque #if (primeras 15 líneas), contiene dos series de directivas #if, #else y #endif anidadas en él. La primera se procesa si es cierta la condición DLEVEL > 5. En caso contrario se procesa la serie situada después del #else.

El resto de líneas del ejemplo se utiliza para establecer el valor de la constante STACK a 0, 100 o 200 en función del valor de la constante DLEVEL, pero si su valor es mayor que 5, STACK queda indefinida, y en su lugar se compila una invocación a la función display utilizando debugptr como argumento.

§5  Operador defined

Tanto Borland C++ como MS VC++ disponen de este operador [1] que solo puede ser utilizado en conjunción con las directivas #if y #elif. Admite dos formas de sintaxis, una de ellas con aspecto de función:

#if   defined ( <identificador> )
#if   defined <identificador>
#elif defined ( <identificador> )
#elif defined <identificador>

§5.1  Descripción

Este operador devuelve cierto (distinto de cero) si identificador ha sido definido previamente mediante una directiva #define ( 4.9.10b). En caso contrario devuelve falso (0).

Como puede verse, cumple la misma función que la directiva #ifdef, de forma que las dos expresiones que siguen son equivalentes:

#if defined identificador
#ifdef identificador

Sin embargo, el operador tiene la ventaja de que permite construir expresiones más complejas en la misma directiva #if o #elif.  Por ejemplo:

#if defined(identif1) && !defined(identifi2)
...
#elif defined(identif1) && defined(identifi2)
...

En el ejemplo siguiente, se utiliza el operador para controlar la compilación de una función entre tres posibilidades:

#if defined(CLIENTE)
  cliente();
#elif defined(PROVEEDOR)
  proveedor();
#else
  printerror();
#endif

Si el identificador CLIENTE ha sido definido, se compila una llamada a la función cliente(). En caso contrario, si se ha definido el identificador PROVEEDOR, se compila una invocación a la función proveedor(); finalmente, en ausencia de alguna de las condiciones anteriores, se invoca la función printerror().

Es frecuente que este operador se utilice para formar directivas de guarda ( 4.9.10e)

  Inicio.


[1]  No incluído en el Estándard C++