Macros en C - Universidad Veracruzana · Macros en C •Usa un preprocesador de macros •Remueve...
Transcript of Macros en C - Universidad Veracruzana · Macros en C •Usa un preprocesador de macros •Remueve...
Macros en C
MIS. Lizbeth Alejandra Hernández González
Programación de Sistemas
Macros en C
• Usa un preprocesador de macros
• Remueve todos los comentarios del código
fuente
• Efectúa una serie de sustituciones conceptuales
basadas en el código pasando el resultado al
compilador.
1. # include <stdio.h>2.3. # define INICIO 0 /* Punto de inicio del bucle */4. # define FINAL 9 /* Fin del bucle */5. # define MAX(A,B) ((A)>(B)?(A):(B)) /* Definición macro de Max */6. # define MIN(A,B) ((A)>(B)?(B):(A)) /* Definición macro de Min */7.8. int main( )9. {10. int indice, mn, mx ;11. int contador = 5 ;12.13. for (indice = INICIO ; indice <= FINAL ; indice++)14. {15. mx = MAX(indice, contador) ;16. mn = MIN(indice, contador) ;17. printf ( "Max es %d y min es %d\n", mx, mn) ;18. }19. return 0 ;20. }
Resultado de la ejecución:
• Max es 5 y min es 0
• Max es 5 y min es 1
• Max es 5 y min es 2
• Max es 5 y min es 3
• Max es 5 y min es 4
• Max es 5 y min es 5
• Max es 6 y min es 5
• Max es 7 y min es 5
• Max es 8 y min es 5
• Max es 9 y min es 5
• #define es la manera para declarar todas las
macros y definiciones.
• el compilador va a la etapa del preprocesador
para resolver todas las definiciones,
• P.e. se buscará cada lugar en el programa
donde se encuentre la palabra INICIO y será
reemplazada con un cero
• El compilador en sí jamás verá la palabra
INICIO.
• Es una práctica común en C utilizar mayúsculas
para constantes simbólicas y minúsculas para
variables.
• cada vez que el preprocesador encuentra la
palabra MAX (termino1, termino2) espera
encontrar dos términos
• el primer término reemplazará cada A en la
segunda parte de la definición, y el segundo
término reemplazará cada B en la segunda
parte de la definición.
• línea 15, indice será sustituída por cada A, y
contador será sustituida por cada B.
• antes de que la línea 15 sea entregada al
compilador, será modificada:
Definición:
# define MAX(A,B) ((A)>(B)?(A):(B))
15 mx = MAX(indice, contador) ;
15 mx = ((index)>(count) ? (index) : (count))
Una macro equivocada
#define EQUIVOCADA(A) A*A*A /* Macro EQUIVOCADA para el cubo */
#define CUBO(A) (A)*(A)*(A) /* Macro correcta para el cubo */
#define CUADRADO(A) (A)*(A) /* Macro correcta para el cuadrado */
#define SUMA_EQUIVOCADA(A) (A)+(A) // Macro equivocada para la suma
#define SUMA_CORRECTA(A) ((A)+(A)) /* Macro correcta para la suma */
#define INICIO 1
#define FINAL 7
int main( ){
int i, offset ;offset = 5 ;for (i = INICIO ; i <= FINAL ; i++){
printf ("El cuadrado de %3d es %4d, y su cubo es %6d\n",i+offset, CUADRADO(i+offset), CUBO(i+offset)) ;printf ("El cubo equivocado de %3d es %6d\n",i+offset, EQUIVOCADA(i+offset)) ;
}printf ("\nProbamos la macro de suma\n") ;for (i = INICIO ; i <= FINAL ; i++){printf ("La macro de suma EQUIVOCADA = %6d, y la correcta = %6d\n",5*SUMA_EQUIVOCADA(i), 5*SUMA_CORRECTA(i)) ;}return 0 ;
}
Necesidad de paréntesis
• Los paréntesis son necesarios para agrupar
adecuadamente las variables.
• Si i es 1 esperamos el cubo de (1+5=6) = 216
• Cuando se usa CUBO(A) (A)*(A)*(A)
▫ (1+5)*(1+5)*(1+5) = 6*6*6 = 216.
• Cuando se usa EQUIVOCADA(A) A*A*A
1+5*1+5*1+5 = 1+5+5+5 = 16
resultado erróneo.
Suma equivocada
▫ #define SUMA_EQUIVOCADA(A) (A)+(A)
▫ #define SUMA_CORRECTA(A) ((A)+(A))
• 5*SUMA_EQUIVOCADA(i) con i=1,
• resultado 5*1+1 5+1= 6,
• el resultado esperado era 5*(1+1) = 5*2 = 10
• usando SUMA_CORRECTA, esto se debe a losparéntesis extra
• NOTA: Agregar paréntesis a cada término y acada expresión (corregir CUBO)
Compilación condicional1. #include <stdio.h>
2. #include <stdlib.h>
3. # define OPCION_1 /* Esto define el control del preprocesador */
4. //# undef OPCION_1
5. # ifdef OPCION_1
6. int contador_1 = 17; /* Esto existe solo si OPCION_1 es definido */
7. # endif
8. int main( )
9. {
10. int indice ;
11. for (indice = 0 ; indice < 6 ; indice++)
12. {
13. printf ("En el bucle, indice = %d", indice) ;
14. # ifdef OPCION_1
15. printf (" contador_1 = %d", contador_1) ; /* puede desplegarse */
16. # endif
17. printf ("\n") ;
18. }
19. system("PAUSE");
20. return 0 ;
21. }
22. # undef OPCION_1
Pruebe el programa
• ¿Cuál es la salida?
• Comente la línea 3
• ¿Cuál es la salida?
• Descomente la línea 3 y descomente la línea 4
• ¿Cuál es la salida?
Ifndef "si no definido".1. #include <stdio.h>
2. #include <stdlib.h>
3. # define OPCION_1 /* Esto define el control al preprocesador */
4. # define MUESTRA_DATO /* Si es definido, se muestra*/
5. # ifndef OPCION_1
6. int contador_1 = 17; /* Esto existe si OPCION_1 no es definido */
7. # endif
8. int main( )
9. {
10. int indice ;
11. # ifndef MUESTRA_DATO
12. printf ("MUESTRA_DATO no está definido en el codigo\n") ;
13. # endif
14. for (indice = 0 ; indice < 6 ; indice++)
15. {
16. # ifdef MUESTRA_DATO
17. printf ("En el bucle, indice = %d", indice) ;
18. # ifndef OPCION_1
19. printf (" contador_1 = %d", contador_1); /* Esto puede mostrarse*/
20. # endif
21. printf ("\n") ;
22. # endif
23. }
24. system("PAUSE");
25. return 0 ;
26. }
Correr el programa
• Verificar la salida original
• Verificar la salida comentando la línea 3
Procesador de macros M4
Procesador de macros M4
• Funciona como el procesador de macros de C.
• Utiliza un lenguaje de macros diferente y de
propósito general; lo cual resulta más potente.
• Ejecutar m4 sin argumentos:
▫ el comando espera texto por la entrada estándar,
▫ tras cada línea introducida, ésta se procesa y se
imprime el resultado por la salida estándar.
• También puede recibir archivos
• La mayor utilidad que se le ha dado a M4 ha
sido en las famosas autotools de GNU
(autoconf, automake, etc.)
• Otro ejemplo es utilizar M4 para escribir
páginas web (creando una abstracción por
encima del HTML).
Utilización de macros
• Llamada a macros:
1. CANTINFLAS
2. Hola señor CANTINFLAS
3. Hola señor CANTINFLAS()puntoycoma.
4. Hola señor CANTINFLAS(punto, y, coma).
5. Hola señor CANTINFLAS(punto y coma).
• La macro que nos permite definir nuevas
macros: define
• admite dos argumentos: el nombre de la nueva
macro y el texto por el que será reemplazada
cada aparición de dicha macro:
▫ define(`CANTINFLAS', 'Bigote')
▫ define(`BOLD', `<b>$1</b>')
Ej. BOLD(hola) será substituido por <b>hola</b>
▫ define(HOLA, Hola mundo cruel)
• $0 que se expande como el nombre de la macro
Otros modificadores
• $* expande todos los argumentos separados por
comas.
• $@ hace lo mismo pero además quotea el
resultado para evitar expansiones del mismo.
• $# se expande como el número de argumentos
pasados a la macro.
Comentarios
• dnl Comentario que no aparecerá en el
resultado.
• # Comentario que sí aparecerá en el resultado
Cadenas protegidas
• Cuando hablamos de una expansión nos referimos a
dos cosas:
▫ Expandir una macro o
▫ Si se trata de un texto rodeado por ` ' simplemente
se eliminan las comillas.
• el proceso de expansión de una macro es recursivo:
1. Expansión de los argumentos.
2. Se procede a la substitución del texto.
3. Se vuelve a procesar el resultado de esta
expansión.
• Saber proteger el texto quoteándolo.
• Para la inclusión de cadenas literales en
el argumento de una macro basta con
rodearla de comillas dobles, p.e.:
▫ define(`CANTINFLAS', `$1')
▫ Hola señor CANTINFLAS(``Y esto aparece tal
cual, metamos lo que metamos'‘)
• Si necesitamos que una macro se expanda entre
texto que no está separado por espacios
podemos usar la cadena vacía `'. Por ejemplo:
• eseCANTINFLASpoderoso (no válido)
• ese`'CANTINFLAS`'poderoso
• anti`'CANTINFLAS()
• M4 tiene macros para implementar
condicionales, como ifdef e ifelse