C++ Preprocesador

El preprocesador es un conjunto de directivas que le indican al compilador el preprocesamiento necesario antes de la compilación real.

Todas las directivas del preprocesador comienzan con el signo de almohadilla (#); solo pueden aparecer caracteres de espacio antes de una directiva de preprocesador. Las directivas de preprocesador no son sentencias de C++, por lo que no terminan con punto y coma (;).

Ya hemos visto que todos los ejemplos anteriores tienen#includela directiva. Esta directiva se utiliza para incluir archivos de cabecera en el archivo fuente.

C++ también admite muchas otras directivas de preprocesador, como #include, #define, #if, #else, #line, etc. Echemos un vistazo a estas directivas importantes.

Preprocesador #define

La directiva de preprocesador #define se utiliza para crear constantes simbólicas. Esta constante simbólica se denomina comúnmentemacro, la forma general de la directiva es:

#define macro-name replacement-text 

Cuando esta línea de código aparece en un archivo, todas las macros que aparezcan posteriormente en ese archivo serán reemplazadas por replacement-text antes de la compilación del programa. Por ejemplo:

#include <iostream> using namespace std; #define PI 3.14159 int main () { cout << "Value of PI :" << PI << endl; return 0; }

Ahora, probemos este código para ver el resultado del preprocesamiento. Suponiendo que el archivo de código fuente ya existe, compile usando la opción -E y redirija el resultado a test.p. Ahora, si examina el archivo test.p, verá que ya contiene una gran cantidad de información, y al final del archivo el valor se ha cambiado a lo siguiente:

$ gcc -E test.cpp > test.p

...
int main ()
{
 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

Macros con parámetros

Puede usar #define para definir una macro con parámetros, como se muestra a continuación:

#include <iostream> using namespace std; #define MIN(a,b) (a<b ? a : b) int main () { int i, j; i = 100; j = 30; cout <<"El valor menor es:" << MIN(i, j) << endl; return 0; }

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

较小的值为:30

Compilación condicional

Hay varias directivas que pueden usarse para compilar selectivamente partes del código fuente del programa. Este proceso se denomina compilación condicional.

La estructura del preprocesador condicional es muy similar a la estructura de selección if. Observe el siguiente código de preprocesador:

#ifdef NULL
   #define NULL 0
#endif

Puede compilar solo en modo de depuración. El conmutador de depuración se puede implementar con una macro, como se muestra a continuación:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

Si la constante simbólica DEBUG ha sido definida antes de la directiva #ifdef DEBUG, entonces se compilaráncerrlas sentencias del programa. Puede usar la directiva #if 0 para comentar parte del programa, como se muestra a continuación:

#if 0
   不进行编译的代码
#endif

Probemos el siguiente ejemplo:

Ejemplo

#include <iostream> using namespace std; #define DEBUG #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; #ifdef DEBUG cerr <<"Trace: Inside main function" << endl; #endif #if 0 /*Esta es la parte comentada*/ cout << MKSTR(HELLO C++) << endl; #endif cout <<"The minimum is " << MIN(i, j) << endl; #ifdef DEBUG cerr <<"Trace: Coming out of main function" << endl; #endif return 0; }

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

Los operadores # y ##

Los operadores de preprocesador # y ## están disponibles tanto en C++ como en C ANSI/ISO. El operador # convierte el token replacement-text en una cadena entre comillas.

Observe la siguiente definición de macro:

Ejemplo

#include <iostream> using namespace std; #define MKSTR( x ) #x int main () { cout << MKSTR(HELLO C++) << endl; return 0; }

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

HELLO C++

Veamos cómo funciona. No es difícil de entender que el preprocesador de C++ convierte la siguiente línea:

cout << MKSTR(HELLO C++) << endl;

en:

cout << "HELLO C++" << endl;

El operador ## se utiliza para concatenar dos tokens. A continuación se muestra un ejemplo:

#define CONCAT( x, y )  x ## y

Cuando CONCAT aparece en el programa, sus parámetros se concatenan y se utilizan para reemplazar la macro. Por ejemplo, en el programa, CONCAT(HELLO, C++) se reemplazará por "HELLO C++", como se muestra en el siguiente ejemplo.

Ejemplo

#include <iostream> using namespace std; #define concat(a, b) a ## b int main() { int xy = 100; cout << concat(x, y); return 0; }

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

100

Veamos cómo funciona. No es difícil de entender que el preprocesador de C++ convierte la siguiente línea:

cout << concat(x, y);

en:

cout << xy;

Macros predefinidas en C++

C++ proporciona algunas macros predefinidas como se muestra en la siguiente tabla:

macro Descripción
__LINE__ Contiene el número de línea actual cuando se compila el programa.
__FILE__ Contiene el nombre del archivo actual cuando se compila el programa.
__DATE__ Contiene una cadena con el formato month/day/year que representa la fecha en que el archivo fuente se convirtió en código objeto.
__TIME__ Contiene una cadena con el formato hour:minute:second que representa la hora en que se compiló el programa.

Veamos algunos ejemplos de estas macros:

Ejemplo

#include <iostream> using namespace std; int main () { cout << "Value of __LINE__ : " << __LINE__ << endl; cout << "Value of __FILE__ : " << __FILE__ << endl; cout << "Value of __DATE__ : " << __DATE__ << endl; cout << "Value of __TIME__ : " << __TIME__ << endl; return 0; }

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48
Otras extensiones