Como sugiere el nombre, los preprocesadores son programas que procesan nuestro código fuente antes de la compilación. Hay una serie de pasos involucrados entre escribir un programa y ejecutar un programa en C/C++. Echemos un vistazo a estos pasos antes de que realmente comencemos a aprender sobre los preprocesadores.
Puede ver los pasos intermedios en el diagrama anterior. El código fuente escrito por los programadores se almacena primero en un archivo, cuyo nombre sea » program.c «. Luego, este archivo es procesado por preprocesadores y se genera un archivo de código fuente expandido llamado «program.i». Este archivo expandido es compilado por el compilador y se genera un archivo de código objeto llamado «program.obj». Finalmente, el enlazador vincula 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 de preprocesador proporcionan directivas de preprocesador que le indican al compilador que procese previamente el código fuente antes de compilar. Todas estas directivas de preprocesador comienzan con un símbolo ‘#’ (almohadilla). El símbolo ‘#’ indica que cualquier declaración que comience con un ‘#’ irá al programa del preprocesador para ejecutarse. Ejemplos de algunas directivas de preprocesador son: #include , #define , #ifndef , etc. Recuerde que el símbolo # solo proporciona una ruta al preprocesador, y un comando como include es procesado por el programa del preprocesador. Por ejemplo, #include incluirá código adicional en su programa. Podemos colocar estas directivas de preprocesador en cualquier lugar de nuestro programa.
Hay 4 tipos principales de directivas de preprocesador:
- macros
- Inclusión de archivos
- compilación condicional
- Otras directivas
Conozcamos ahora cada una de estas directivas en detalle.
1. macros
Las macros son fragmentos de código en un programa al que se le da algún nombre. Cada vez que el compilador encuentra este nombre, el compilador reemplaza el nombre con el código real. La directiva ‘#define’ se usa para definir una macro. Entendamos ahora la definición de macro con la ayuda de un programa:
C++
#include <iostream> // macro definition #define LIMIT 5 int main() { for (int i = 0; i < LIMIT; i++) { std::cout << i << "\n"; } return 0; }
C
#include <stdio.h> // macro definition #define LIMIT 5 int main() { for (int i = 0; i < LIMIT; i++) { printf("%d \n",i); } return 0; }
Producción:
0 1 2 3 4
En el programa anterior, cuando el compilador ejecuta la palabra LIMIT, la reemplaza con 5. La palabra ‘LIMIT’ en la definición de macro se llama plantilla de macro y ‘5’ es expansión de macro.
Nota : No hay punto y coma (;) al final de la definición de la macro. Las definiciones de macro 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 manera similar a las funciones. Entendamos esto con un programa:
C++
#include <iostream> // macro with parameter #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> // macro with parameter #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; }
Producción:
Area of rectangle is: 50
Podemos ver en el programa anterior que cada vez que el compilador encuentra AREA(l, b) en el programa, lo reemplaza con la instrucción (l*b). No solo esto, sino que los valores pasados a la plantilla de macro AREA(l, b) también serán reemplazados en la instrucción (l*b). Por lo tanto AREA(10, 5) será igual a 10*5.
2. Inclusión de archivos
Este tipo de directiva de preprocesador le dice al compilador que incluya un archivo en el programa de código fuente. Hay dos tipos de archivos que el usuario puede incluir en el programa:
archivos de encabezado o archivos estándar : estos archivos contienen definiciones de funciones predefinidas como printf(), scanf(), etc. Estos archivos deben incluirse para funcionar. con estas funciones. Las diferentes funciones se declaran en diferentes archivos de encabezado. Por ejemplo, las funciones de E/S estándar están en el archivo ‘iostream’ mientras que las funciones que realizan operaciones de string están en el archivo ‘string’.
Sintaxis :
#include< file_name >
donde file_name es el nombre del archivo que se incluirá. Los corchetes ‘<‘ y ‘>’ le indican al compilador que busque el archivo en el directorio estándar.
Archivos definidos por el usuario : cuando un programa se vuelve muy grande, es una buena práctica dividirlo en archivos más pequeños e incluirlos cuando sea necesario. Estos tipos de archivos son archivos definidos por el usuario. Estos archivos se pueden incluir como:
#include"filename"
3. Compilación condicional
Las directivas de compilación condicional son un tipo de directiva que ayuda a compilar una parte específica del programa oa omitir la compilación de alguna parte específica del programa en función de algunas condiciones. Esto se puede hacer con la ayuda de los dos comandos de preprocesamiento ‘ ifdef ‘ y ‘ endif ‘.
Sintaxis :
#ifdef macro_name statement1; statement2; statement3; . . . statementN; #endif
Si se define la macro con el nombre ‘ macro_name ‘, entonces el bloque de sentencias se ejecutará normalmente, pero si no se define, el compilador simplemente omitirá este bloque de sentencias.
4. Otras Directivas
Además de las directivas anteriores, hay dos directivas más que no se usan comúnmente. Estos son:
Directiva #undef : La directiva #undef se utiliza para anular la definición de una macro existente. Esta directiva funciona como:
#undef LIMIT
El uso de esta declaración anulará la definición del límite de macro existente. Después de esta declaración, cada declaración «#ifdef LIMIT» se evaluará como falsa.
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 analizan 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 los compiladores GCC.
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; } // This code is contributed by shivanisinghss2110
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; }
Producción:
Inside func1() Inside main() Inside func2()
El código anterior producirá el resultado que se indica a continuación cuando se ejecute en compiladores GCC:
Inside main()
Esto sucede porque GCC no admite el inicio o la salida de #pragma. Sin embargo, puede usar el siguiente código para obtener un resultado similar en los compiladores de GCC.
C++
#include <iostream> using namespace std; void func1(); void func2(); void __attribute__((constructor)) func1(); void __attribute__((destructor)) func2(); void func1() { printf("Inside func1()\n"); } void func2() { printf("Inside func2()\n"); } // Driver code int main() { printf("Inside main()\n"); return 0; } // This code is contributed by Shivani
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; }
Directiva #pragma warn: esta directiva se utiliza para ocultar el mensaje de advertencia que se muestra durante la compilación. Podemos ocultar las advertencias como se muestra a continuación:
- #pragma warn -rvl : esta directiva oculta las advertencias que se generan cuando una función que se supone que debe devolver un valor no devuelve un valor.
- #pragma warn -par : esta directiva oculta las advertencias que se generan cuando una función no usa los parámetros que se le pasan.
- #pragma warn -rch : esta directiva oculta las advertencias que se generan cuando no se puede acceder a un código. Por ejemplo, cualquier código escrito después de la declaración de devolución en una función es inalcanzable.
Este artículo es una contribución de Harsh Agarwal . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a contribuir@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA