Bienvenidos sean a este post, hoy veremos un tema heredado de C.
Los preprocessor son una serie de rutinas pensadas en dejar lista para ser compilados. Estos trabajan mediante directivas de preprocessor. Algunas ya las hemos visto: #include, #define, #pragma once. Si bien estas no representan instrucciones de programas, si son comandos para el preprocessor para indicarle que hacer con el codigo fuente. Estas no son reconocidas por el compilador, por lo tanto cualquiera que usemos sera resuelta antes que la compilacion del codigo comience. Vamos a suponer el siguiente ejemplo:
#define NUMERO 41
#include <iostream>
int main()
{
std::cout << NUMERO + 2 << std::endl;
return 0;
}
En este caso todo lo que pasemos mediante una directiva preprocessor se lo denomina como macro. Siendo que en realidad, este se pre-procesara antes de compilarlo. Por lo cual convertira el codigo anterior en el siguiente:
int main()
{
std::cout << 41 + 2 << std::endl;
return 0;
}
Donde el valor de #define lo pasa a donde lo usamos y el #include cargara el archivo que le pasemos. Y como nuestro compilador no sabe como interpretarlos ya no son parte del codigo. Pero si ven, al momento de utilizarlo, le pasa el valor que tiene asignado. En C se lo utilizaba para que trabajen de una forma similar a una constante. Porque no hay forma de modificar este valor y se aplica en todos los lugares que lo usemos. Pero esto tiene un inconveniente, sin importar el valor que le asignemos este no siempre sera usado correctamente por el codigo. Porque al no ser parte del mismo, no le definimos el tipo de informacion y si un valor. Veamos el siguiente caso:
int b = NUMERO + 1;
struct N {};
N t = NUMERO;
Vamos a asumir que tenemos la misma macro que en el codigo anterior. Por lo tanto, la primera linea se compilara con exito. Porque el valor informado al ser numerico y pasarlo a un tipo int no tendra ningun inconveniente. Luego establecemos un «nuevo» tipo para nuestro codigo. Creamos un objeto de este tipo y le asignamos la macro. Este se pre-procesara correctamente pero fallara en la compilacion porque al no tener un tipo asignado no seran compatibles. La ultima linea se convertiria en lo siguiente:
N t = 41;
Pero usar este tipo de directivas tambien puede generar inconvenientes. Vamos a tomar el codigo original y lo modificaremos de la siguiente manera:
#define NUMEROS(arg) (arg * arg)
#include <iostream>
int main()
{
int numero = NUMEROS(4);
std::cout << numero << std::endl;
return 0;
}
Miremos principalmente el caso del #define. Pasamos el nombre seguido de la posibilidad de recibir un valor como argumento. Y ese argumento lo multiplicaremos entre si para obtener un valor al cuadrado. En el main, definimos una variable que almacenara el valor devuelto por la macro. Y finalmente, lo mostraremos. Si lo compilan y ejecutan nos mostrara en consola un valor de 16. El cuadrado de 4 porque modificara a la variable de la siguiente manera:
int numero = ( 4 * 4 );
Pero que sucedera si modificamos a la variable de la siguiente manera:
int numero = NUMEROS(4 + 1);
Al momento de procesarlo, enviara esa formula y no el resultado para que sea multiplicado. Que valor creen que nos devolvera, 9 o 25? Si pensaron en 25, se equivocaron porque al reemplazarlo sera de la siguiente manera:
int numero = ( 4 + 1 * 4 + 1 );
Por lo tanto, hara primero la multiplicacion de 1 y 4. A este valor le sumara los otros dos valores, dando como resultado 9. Pero si en lugar de pasarlo directamente lo hicieramos de la siguiente manera:
int numero = NUMEROS((4 + 1));
Al pasar los parentesis para que quede aislada cada formula, si procedera primero a resolver cada formula y luego multiplicarlas entre ellas. Por estos pequeños inconvenientes que pueden surgir al momento de pasar valores, no es recomendable usar esta directiva para declarar constantes sino mas bien mediante el uso de la palabra const, tal como vimos en este post.
Si bien, algunas directivas seran usadas para ciertos temas. Por ejemplo, cuando aplicamos #pragma once en los archivos de encabezado o mismo #include para importar librerias. Para otras directivas heredadas de C es preferible usar instrucciones propias del lenguaje para lograr el mismo resultado y evitar inconvenientes como citamos anteriormente.
En resumen, hoy hemos visto preprocessor, que es, para que sirve, mencionamos algunas de las disponibles y que hemos usado, asi como tambien vimos un pequeño ejemplo de como aplicarla y un inconveniente que puede surgir. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donatión
It’s for site maintenance, thanks!
$1.50
