HOW-TO: Macros en C (II) – «funciones»

Publicado por Alejandro Escario en

En el pasado y primer artículo de esta serie, describimos a grosso modo el funcionamiento de la directiva de preprocesador #define; siendo una de las características más importantes a tener en cuenta el hecho de que a la hora de compilar el programa no estamos trabajando con variables con un valor, sino con los valores directamente. De este modo estaremos ahorrando memoria y dotando de legibilidad a nuestro código en determinadas ocasiones.

Hoy vamos a ver cómo simular funciones con el sistema de Macros. Antes de nada, hay que aclarar que: si bien para constantes, por convenio, se utilizan letras mayúsculas en todo momento, para esta especie de funciones no es necesario hacer esto, de manera que podemos continuar con el sistema de nomenclaturas que hemos estado llevando hasta el momento (como recomendación, yo usaría todo en minúsculas menos la primera letra de cada palabra exceptuando la de la primera, Ex: hallarMaximo(…)).

Supongamos que contamos con dos funciones en nuestras librerías:

int rand(void);
int fastRand(void);

Ambas funciones llevan a cabo la misma tarea, sólo que utilizan diferentes métodos para realizarla, de hecho, la segunda que es mucho más eficiente que la primera (como puede entenderse por el nombre), la acabamos de implementar y, a pesar de que la entrada y la salida es la misma, la primera ha sido utilizada cientos de veces en nuestro código, y cambiarla implicaría un repaso exhaustivo del código fuente y, en caso de tener una API pública, implicaría cambiarla y notificárselo a todos nuestros usuarios.

En lugar de esto, podemos crear una macro que se encargue de realizar dicha sustitución durante el proceso de precompilado:

#define rand() fastRand()

de manera que, cada vez que llamemos a la función rand() en nuestro código, a la hora de compilarlo, es como si estuviésemos llamando a la función fastRand().

Pero el poder de esta herramienta no se para con estas características, sino que nos permite definir algo parecido a funciones de forma completa. Con esto quiero decir que podemos definir macros que a la hora de editar el código y utilizarlos, podemos asumir que son funciones. Pongamos un ejemplo:

#define max(x, y) ((x > y) ? x : y)

una vez hehcha esta definición, nosotros, desde nuestro código podremos llamar a esta “función” evitando que se gasten, entre otras cosas niveles de pila, ya que el código es sustituido durante el proceso de preprocesado, de manera que si escribimos en nuestro código:

int a = 2;
int b = 4;
int z = max(a, b);

el código que realmente se estará ejecutando una vez compilado será:

int a = 2;
int b = 4;
int z = ((a > b) ? a : b);

Uno de los grandes problemas de utilizar esta técnica para sustituir a las funciones es que, como podemos observar es que, a la hora de llamar a la macro, no tenemos comprobación del tipado de los datos que le pasamos, pudiendo obtener así, resultados inesperados o incluso errores de estabilidad del programa. Hay que ser conscientes en todo momento de que los argumentos, a la hora de llamar a una macro que se comporta por una función, estarán separados por comas.

Finalmente, a la hora de llamar a una macro, si no le pasamos el número de argumentos necesarios, obtendremos un error de preprocesador, pero en caso de que le pasemos argumentos vacíos, estos se sustiuirán por argumentos vacíos sin dar error durante el proceso de preprocesado.

Categorías: C/C++Manuales

1 comentario

Gustavo Rosario · septiembre 28, 2014 a las 1:01 am

Gracias por todo esto, es de gran ayuda.

Los comentarios están cerrados.