Como su nombre indica los Preprocesadores son programas que procesan nuestro código fuente antes de la compilación. Hay una serie de pasos involucrados entre la escritura de un programa y la ejecución de un programa en C / C ++. Echemos un vistazo a estos pasos antes de empezar a aprender sobre los Preprocesadores.

Puedes ver los pasos intermedios en el diagrama anterior. El código fuente escrito por los programadores se almacena en el archivo program.c. Este archivo es procesado por los preprocesadores y se genera un archivo de código fuente expandido llamado program. Este archivo expandido es compilado por el compilador y se genera un archivo de código objeto llamado programa.obj. Finalmente, el enlazador enlaza este archivo de código objeto con el código objeto de las funciones de la biblioteca para generar el archivo ejecutable program.exe.

Los programas preprocesadores proporcionan directivas de preprocesadores que indican al compilador que debe preprocesar el código fuente antes de la compilación. Todas estas directivas del preprocesador comienzan con un símbolo ‘#’ (hash). El símbolo ‘#’ indica que, cualquier declaración que comience con #, va al programa preprocesador, y el programa preprocesador ejecutará esta declaración. Ejemplos de algunas directivas del preprocesador son: #include, #define, #ifndef etc. Recuerde que el símbolo # sólo proporciona una ruta que irá al preprocesador, y el comando como include es procesado por el programa preprocesador. Por ejemplo, include incluirá código extra a su programa. Podemos colocar estas directivas del preprocesador en cualquier parte de nuestro programa.

Hay 4 tipos principales de directivas de preprocesador:

  1. Macros
  2. Inclusión de archivos
  3. Compilación condicional
  4. Otras directivas

Conocemos ahora cada una de estas directivas en detalle.

  • Macros: Las macros son un trozo de código en un programa al que se le da algún nombre. Cada vez que el compilador encuentra este nombre, sustituye el nombre por el fragmento de código real. La directiva ‘#define’ se utiliza para definir una macro. Entendamos ahora la definición de la macro con la ayuda de un programa:
C++

#include <iostream>
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
std::cout << i << "\n";
}
return 0;
}



C

#include <stdio.h>
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
printf("%d \n",i);
}
return 0;
}



Salida:

01234

En el programa anterior, cuando el compilador ejecuta la palabra LIMIT la sustituye por 5. La palabra ‘LIMIT’ en la definición de la macro se llama plantilla de macro y ‘5’ es la expansión de la macro.

Nota: No hay punto y coma(‘;’) al final de la definición de la macro. Las definiciones de macros no necesitan un punto y coma para terminar.

Macros con argumentos: También podemos pasar argumentos a las macros. Las macros definidas con argumentos funcionan de forma similar a las funciones. Entendamos esto con un programa:

C++

#include <iostream>
#define AREA(l, b) (l * b)
int main()
{
int l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
std::cout << "Area of rectangle is: " << area;
return 0;
}



C

#include <stdio.h>
#define AREA(l, b) (l * b)
int main()
{
int l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
printf("Area of rectangle is: %d", area);
return 0;
}



Salida:

Area of rectangle is: 50

Podemos ver en el programa anterior que, siempre que el compilador encuentra AREA(l, b) en el programa lo sustituye por la sentencia (l*b) . No sólo esto, los valores pasados a la macro plantilla AREA(l, b) también serán reemplazados en la sentencia (l*b). Por lo tanto, AREA(10, 5) será igual a 10*5.

  • Inclusión de archivos: Este tipo de directiva de preprocesador indica al compilador que incluya un archivo en el programa de código fuente. Hay dos tipos de archivos que pueden ser incluidos por el usuario en el programa:
    • Archivo de cabecera o archivos estándar: Estos archivos contienen la definición de funciones predefinidas como printf(), scanf() etc. Estos archivos deben ser incluidos para trabajar con estas funciones. Diferentes funciones son declaradas en diferentes archivos de cabecera. Por ejemplo, las funciones estándar de E/S están en el archivo ‘iostream’ mientras que las funciones que realizan operaciones de cadena están en el archivo ‘string’.
      Sintaxis:
#include< file_name >

donde nombre_archivo es el nombre del archivo que se va a incluir. Los paréntesis ‘<‘ y ‘>’ indican al compilador que busque el archivo en el directorio estándar.

  • archivos definidos por el usuario: Cuando un programa se hace muy grande, es una buena práctica dividirlo en archivos más pequeños e incluirlos siempre que sea necesario. Este tipo de archivos son los archivos definidos por el usuario. Estos archivos se pueden incluir como:
#include"filename"
  • Compilación condicional: Las directivas de compilación condicional son un tipo de directivas que ayudan a compilar una parte específica del programa o a omitir la compilación de alguna parte específica del programa basándose en algunas condiciones. Esto se puede hacer con la ayuda de dos comandos de preprocesamiento ‘ifdef’ y ‘endif’.
    Sintaxis:

#ifdef macro_name statement1; statement2; statement3; . . . statementN;#endif

Si la macro con nombre como está definida entonces el bloque de sentencias se ejecutará normalmente pero si no está definida, el compilador simplemente saltará este bloque de sentencias.

  • Otras directivas: Aparte de las directivas anteriores hay dos directivas más que no son de uso común. Estas son:
    • Directiva #undef: La directiva #undef se utiliza para indefinir una macro existente. Esta directiva funciona como:
#undef LIMIT

Usando esta sentencia se indefinirá la macro existente LIMIT. Después de esta declaración cada declaración «#ifdef LIMIT» se evaluará a falso.

  • #directiva pragma: Esta directiva es una directiva de propósito especial y se utiliza para activar o desactivar algunas características. Este tipo de directivas son específicas del compilador, es decir, varían de un compilador a otro. Algunas de las directivas #pragma se discuten a continuación:
    • #pragma startup y #pragma exit: Estas directivas nos ayudan a especificar las funciones que se necesitan ejecutar antes del inicio del programa( antes de que el control pase a main()) y justo antes de la salida del programa (justo antes de que el control regrese de main()).
      Nota: El siguiente programa no funcionará con compiladores GCC.
      Mira el siguiente programa:
C++

#include <bits/stdc++.h>
using namespace std;
void func1();
void func2();
#pragma startup func1
#pragma exit func2
void func1()
{
cout << "Inside func1()\n";
}
void func2()
{
cout << "Inside func2()\n";
}
int main()
{
void func1();
void func2();
cout << "Inside main()\n";
return 0;
}



C

#include <stdio.h>
void func1();
void func2();
#pragma startup func1
#pragma exit func2
void func1()
{
printf("Inside func1()\n");
}
void func2()
{
printf("Inside func2()\n");
}
int main()
{
void func1();
void func2();
printf("Inside main()\n");
return 0;
}



Salida:

Inside func1()Inside main()Inside func2()

El código anterior producirá la salida que se indica a continuación cuando se ejecute en los compiladores GCC:

Inside main()

Esto ocurre porque GCC no soporta #pragma startup o exit. Sin embargo, puede utilizar el siguiente código para obtener una salida similar en los compiladores GCC.

C

#include <stdio.h>
void func1();
void func2();
void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
void func1()
{
printf("Inside func1()\n");
}
void func2()
{
printf("Inside func2()\n");
}
int main()
{
printf("Inside main()\n");
return 0;
}



  • #pragma warn Directiva: Esta directiva se utiliza para ocultar los mensajes de advertencia que se muestran durante la compilación.
    Podemos ocultar las advertencias como se muestra a continuación:
    • #pragma warn -rvl: Esta directiva oculta las advertencias que se producen cuando una función que debe devolver un valor no lo hace.
    • #pragma warn -par: Esta directiva oculta los avisos que se producen cuando una función no utiliza los parámetros que se le pasan.
    • #pragma warn -rch: Esta directiva oculta aquellas advertencias que se levantan cuando un código es inalcanzable. Por ejemplo: cualquier código escrito después de la declaración de retorno en una función es inalcanzable.

Este artículo ha sido contribuido por Harsh Agarwal. Si te gusta GeeksforGeeks y quieres contribuir, también puedes escribir un artículo en contribute.geeksforgeeks.org o enviar tu artículo por correo a [email protected]. Verás tu artículo en la página principal de GeeksforGeeks y ayudarás a otros Geeks.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.