DEFINES Y MACROS en C

| 2013-04-23 | No hay comentarios »

DEFINES Y MACROS: AYUDA A UNA PROGRAMACIÓN CLARA

A continuación vemos el primer ejemplo de algunas «defines» y «macros»:

19DEFINE.C


#define START  0  /* Punto de comienzo del bucle */

#define ENDING 9  /* Punto de final del bucle */

#define MAX(A,B)  ((A)>(B)?(A):(B))  /* Macro definitoria de Max */

#define MIN(A,B)  ((A)>(B)?(B):(A))  /* Macro definitoria de Min */

 

main()

{

int index,mn,mx;

int count = 5;

 

for (index = START;index <= ENDING;index++) {

mx = MAX(index,count);

mn = MIN(index,count);

printf("Max es %d y min es %d\n",mx,mn);

}

}

&nbsp;

Observamos que las 4 primeras líneas de programa empiezan con la palabra «#define«. Es la manera de definir todos los «macros» y las «defines«. Antes de empezar la compilación, el compilador efectúa un paso de preprocesador para resolver todas las «defines». En el caso presente encontrará cada sitio donde la combinación «START» aparezca y, simplemente la sustituirá por un 0, ya que esto es una definición. El compilador nunca verá la palabra «START» en toda la compilación. Sólo encontrará ceros.

En este caso se utilizan las palabras «START», «ENDING», etc. Pero pueden utilizarse las que se quiera, como «INICIO», «FIN», etc.

En el caso de un programa pequeño, como este, no tiene importancia lo que se use, pero imagínese un programa de 2000 líneas y 27 referencias a START. Sería totalmente distinto. Si necesitara cambiar todos los STARTS del programa por un nuevo número, no habría dificultad en hacerlo con un «#define», pero más complicado sería cambiar todas las referencias manualmente, y realmente desastroso si se deja un par de referencias.

De la misma manera, el preprocesador encontrará todas las apariciones de la palabra «ENDING», y las cambiará por 9, y el compilador operará en esa línea sin saber que hubo un «ENDING».

Es una buena costumbre en programación el usar mayúsculas para constantes simbólicas, como «START» y «ENDING», y usar minúsculas para las variables. Per puede usarse el método que se prefiera, es a gusto de cada uno.

¿ESTO ES ÚTIL?

Cuando en adelante tratemos sobre entrada/salida, necesitaremos alguna manera de conocer el fin de fichero, en un fichero de entrada. Dado que diferentes compiladores usan distintos valores numéricos para esto, a pesar de que lo más usual es usar 0 o -1, escribiremos un programa con «define» para  definir el EOF(fin de fichero) para nuestro compilador.

Si tras un tiempo cambiamos de intérprete C, será cuestión de modificar la define de acuerdo con el nuevo compilador. Fin de fichero es otro de los indicadores no universales.

Esto tendrá sentido en temas posteriores.

¿QUÉ ES UN MACRO?

Un macro no es más que otro define, pero dado que es capaz, o al menos susceptible de realizar decisiones lógicas, o funciones matemáticas, tiene un nombre único.

Consideremos la tercera línea del programa como un ejemplo de macro. En este caso, si alguna vez el preprocesador encuentra la palabra «MAX» seguida de un grupo de paréntesis, esperará a encontrar dos términos entre paréntesis, y realizará una sustitución de los términos en la segunda definición. Entonces, el primer termino reemplazará cada «A» en la segunda definición, y el segundo término sustituirá cada «B» en la segunda definición. Cuando encontramos la línea 12 del programa, «index» será sustituido por cada «A», y «count» lo será por cada «B». Recordando la estructura críptica, estudiada anteriormente, revelaremos que «mx» recibirá el máximo valor de «index» o «count». De una manera parecida, el macro «MIN» resultará en «mn», recibiendo el mínimo valor de «index» o «count». Los resultados aparecen por pantalla. Hay bastantes paréntesis extra en la definición del macro, pero no sobran, son esenciales.

UN MACRO INCORRECTO

El siguiente es un ejemplo mejor de macro:

20MACRO.C


#define WRONG(A) A*A*A      /* Macro incorrecto para el cubo */

#define CUBE(A) (A)*(A)*(A) /* Macro correcto para el cubo */

#define SQUR(A) (A)*(A)     /* Macro correcto para el cuadrado */

#define START 1

#define STOP  9

&nbsp;

main()

{

int i,offset;

&nbsp;

offset = 5;

for (i = START;i <= STOP;i++) {

printf("El cuadrado de %3d es %4d, y su cubo es %6d\n",

i+offset,SQUR(i+offset),CUBE(i+offset));

printf("El incorrecto de  %3d es %6d\n",i+offset,WRONG(i+offset));

}

}

La primera línea define un macro de nombre «WRONG», que sirve para obtener el cubo de «A», y de hecho lo hace en algunos casos, aunque fracasando estrepitosamente en otros. El segundo macro, llamado «CUBE» obtiene el cubo en todos los casos.

Consideremos el programa en si, donde el CUBE de i+offset es calculado. Si i es 1, lo cual es la primera vez, buscaremos el cubo de 1+5+6, el cual es 216. Cuando usamos «CUBE» agrupamos valores como estos: (1+5)*(1+5)*(1+5) = 6*6*6 =216. Como siempre, si usamos WRONG, los agruparemos así: 1+5*1+5*1+5 = 1+5+5+5 = 16, lo cual es una respuesta incorrecta. Los paréntesis son básicos para operar con variables agrupadas. Debe ver bien clara la diferencia entre «CUBE» y «WRONG». Los valores correctos e incorrectos de cubo y cuadrado aparecen por pantalla para su inspección.

El resto del programa es simple, y no necesita comentarios.

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.

Posts Relacionados

  • RPC (Remote Procedure Call) en C – Linux
  • Sockets en C (Parte II) – Linux
  • Sockets en C (Parte I) – Linux
  • Pipes en C – Linux



SEGUÍNOS EN FACEBOOK


GITHUB