| Versión 3.0 |
| 800x600 mínimo |
|
En esta lección: Uso del preprocesador ----- Macros ----- Compilación condicional ----- Variables enum ----- Otras secciones: Conceptos básicos ----- Programando en C ----- Programando en C++ ----- Programando Windows 9x. ----- Teoría electrónica ----- Circuitos electrónicos ----- Actividades adicionales ----- Hipervínculos ----- Contácteme: Dudas y comentarios ----- |
Ayuda a programar con limpiezaEl preprocesador es un programa que se ejecuta justa antes de la ejecución del compilador, su operación es transparente para Usted pero hace un trabajo muy importante al remover todos los comentarios del código fuente y efectuando una serie de sustituciones conceptuales basadas en su código pasando el resultado al compilador.
Observe las líneas 3 a 6, cada una comienza con #define. Esta es la manera para declarar todas las macros y definiciones. Antes de iniciar el proceso de compilación, el compilador vá a la etapa del preprocesador para resolver todas las definiciones, en el presente caso, se buscará cada lugar en el programa donde se encuentre la palabra INICIO y será reemplazada con un cero porque así está definido. El compilador en sí jamás verá la palabra INICIO. Observe que si la palabra se encuentra en una cadena o en un comentario, esta no será cambiada. Debe quedarle claro que al poner la palabra INICIO en lugar del número 0 es solo por conveniencia para Usted actuando como comentario ya que la palabra INICIO ayuda a entender el uso del cero. Es una práctica común en la programación C utilizar letras mayúsculas para representar constantes simbólicas y utilizar letras minúsculas para los nombres de las variables. Usted puede utilizar el estilo de letra que mas le guste ya que esto es materia de gusto personal. ¿Qué es una macro?Una macro no es otra cosa que una definición, pero como parece ser capaz de ejecutar algunas decisiones lógicas ú operaciones matemáticas, tiene un nombre único. En la línea 5 del programa podemos ver un ejemplo de una macro, en este caso, cada vez que el preprocesador encuentra la palabra MAX seguida por un grupo de paréntesis espera encontrar dos términos en el paréntesis y hará el reemplazo de los términos en la segunda parte de la definición, así 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. Cuando el programa alcanza la línea 15, indice será sustituída por cada A, y contador será sustituida por cada B. Por lo tanto, antes de que la línea 15 sea entregada al compilador, esta será modificada por lo siguiente:
Recuerde que ni los comentarios ni las cadenas serán afectadas. Recordando las construcciones ya estudiadas vemos que mx recibirá el valor máximo de indice ó contador. De la misma manera, la macro MIN resulta en mn recibiendo el valor mínimo de indice ó contador. Estas dos macros se utilizan con frecuencia en los programas C. Al definir una macro es imperativo que no haya espacio entre el nombre de la macro y el paréntesis de apertura, de lo contrario, el compilador no podrá determinar la existencia de una macro pero sí hará la sustitución definida. Los resultados de la macro se imprimen en la línea 17. Una macro equivocadaEn el siguiente código podemos observar que la línea 3 define una macro llamada EQUIVOCADA que aparentemente calcula el cubo de A, y en algunos casos lo hace, pero falla miserablemente en otros casos. La segunda macro llamada CUBO obtiene el cubo pero no en todos los casos, mas adelante estudiaremos el porque falla en algunas situaciones, el código es el siguiente:
![]()
Considere el programa mismo donde el CUBO de i+offset se calcula en la línea 19. Si i es 1, entonces estaremos buscando el cubo de 1+5=6, lo cual resulta en 216. Cuando se usa CUBO, los valores se agrupan así, (1+5)*(1+5)*(1+5)=6*6*6=216. Sin embargo, al utilizar EQUIVOCADA tenemos el siguiente agrupamiento, 1+5*1+5*1+5=1+5+5+5=16 lo que dá un resultado erróneo. Los paréntesis son necesarios para agrupar adecuadamente las variables. En la línea 6 definimos la macro SUMA_EQUIVOCADA de acuerdo a las reglas dadas pero aún tenemos problemas cuando tratamos de utilizar esta macro en las líneas 27 y 28. En la línea 28, cuando queremos que el programa calcule 5*SUMA_EQUIVOCADA(i) con i=1, obtenemos como resultado 5*1+1, lo que se evalúa como 5+1 ó 6, y esto seguramente no es lo que tenemos en mente, el resultado que realmente deseamos es 5*(1+1) = 5*2 = 10 que es la respuesta que obtenemos al utilizar la macro llamada SUMA_CORRECTA, esto se debe a los paréntesis extra que agregamos en la definición dada en la línea 7. Dedicarle un poco de tiempo para estudiar este programa nos ayudará a comprender el funcionamiento de las macros. Para prevenir los problemas que hemos visto en el ejemplo, los programadores experimentados de C incluyen un paréntesis en torno a cada variable en una macro y un paréntesis adicional en torno a la totalidad de la expresión, esto permitirá a cualquier macro trabajar adecuadamente y esta es la razón por la que la macro CUBO arroja ciertos resultados erróneos, necesita un paréntesis en torno a la expresión. Compilación condicional (Parte 1).Analizemos ahora el concepto de compilación condicional en el código siguiente. Se define OPCION_1 en la línea 3, y se considera definida por el resto del programa, cuando el preprocesador alcanza la línea 5 mantiene el texto comprendido entre las líneas 5 y 7 en el programa y lo pasa al compilador. Si OPCION_1 no hubiera sido definido en la línea 5, el preprocesador se hubiera brincado la línea 6 y el compilador jamás la hubiera visto. Similarmente la línea 17 es condicionalmente compilada siempre que OPCION_1 lo sea. Esta es una construcción muy útil pero no en la manera en que la usamos en el ejemplo, generalmente se utiliza para incluír una característica si estamos utilizando cierto tipo de procesador, o cierto tipo de sistema operativo o aún una pieza especial de hardware.
Compile y ejecute el programa como está, después comente la línea 3 de tal manera que OPCION_1 no sea definida entonces recompile y ejecute el programa, verá como la línea extra no se imprimirá porque el preprocesador se la brincó. En la línea 25 ilustramos el comando al preprocesador undefine. Este remueve el hecho de que OPCION_1 fue definido y desde este punto el programa actúa como si nunca hubiera sido definido, por supuesto que la instrucción undefine nada tiene que hacer en este punto del programa ya que éste está completo y no siguen mas enunciados ejecutables, como experimento coloque la instrucción undefine en la línea 4, recompile y ejecute el programa y verá que actúa como si OPCION_1 jamás hubiera sido definido. Compilación condicional (Parte 2).En el siguiente programa ilustramos la directiva al preprocesador ifndef que se lee literalmente "si no definido". El programa de ejemplo siguiente representa un ejercicio real de lógica para el estudiante diligente y no debe representar problema alguno comprender el uso de la instrucción ifndef.
Compilación condicional (Parte 3).El siguiente programa ilustra un uso práctico del preprocesador. En este programa definimos un símbolo llamado EN_PROCESO, cuando llegamos al código de la función main ( ) vemos el porque está definido. Aparentemente no tenemos suficiente información para completar este código por lo que decidimos separar el código hasta tener una oportunidad de hablar con Martín y Martha acerca de cómo completar estos cálculos, mientras tanto deseamos continuar trabajando en otras partes del programa por lo que utilizamos el preprocesador para temporalmente brincarnos esta parte incompatible del código, debido al mensaje que colocamos en la línea 14 es imposible olvidar que debemos regresar y limpiar el código. Veamos el ejemplo:
En este caso solo hemos tratado con unas cuantas líneas de código. Podemos utilizar esta técnica para manejar varios bloques de código, algunos de los cuales pueden estar en otros módulos, hasta que Martín regrese a explicar el análisis y así poder completar los bloques indefinidos. Programas con múltiples archivosPara programas pequeños es conveniente incluir todo el código en un solo archivo y compilarlo para obtener el resultado final, sin embargo, la gran mayoría de los programas C son muy grandes para incluirlos en un solo archivo y trabajar cómodamente. Es normal encontrar un programa compuesto de varios archivos y es necesario para estos archivos comunicarse y trabajar juntos en un solo programa grande. Aunque es mejor no utilizar variables globales, algunas veces es conveniente su uso. Algunas de estas variables necesitan ser referenciadas por dos o mas archivos diferentes, C provee una manera de hacer esto. Considere las siguientes tres porciones de código.
La variable llamada indice definida en Archivo1.c está disponible para utilizarse por cualquier otro archivo porque está definida globalmente. Los otros dos archivos hacen uso de la misma variable al declararla variable de tipo extern. En escencia se le está diciendo al compilador, "deseo utilizar la variable llamada indice la cual está definida en algún lugar". Cada vez que indice sea referenciada en los otros dos archivos, la variable de ese nombre es utilizada de Archivo1.c, y puede ser leída y modificada por cualquiera de los tres archivos, esto provee una manera fácil para intercambiar datos de un archivo a otro pero puede causar problemas. La variable llamada contador esta definida en Archivo2.c y esta referida en Archivo1.c como explicamos arriba, pero no puede utilizarse en Archivo3.c porque aquí no está declarada. Una variable estática, como valor en Archivo2.c no puede ser referenciada por ningún otro archivo. Otra variable llamada valor está definida en Archivo3.c, esta no tiene ninguna relación con la variable del mismo nombre en Archivo2.c. En este caso, Archivo1.c puede declarar una variable externa valor y hacer referencia a esta variable en Archivo3.c si se desea. El punto de entrada main ( ) solo puede ser llamado por el sistema operativo para iniciar el programa, pero las funciones dos ( ) y tres ( ) pueden ser llamadas desde cualquier punto dentro de los tres archivos ya que son funciones globales. Sin embargo, como la función uno ( ) esta declarada como de tipo estática solo puede ser llamada dentro del archivo en la cual esta declarada. ¿Qué es una variable enumerada?Veamos en el siguiente código un ejemplo de cómo utilizar la variable de tipo enum.
La línea 5 define una variable de tipo enum llamada numero. Esta variable puede tomar cualquier valor de los especificados dentro de las llaves. Si no se especifica un valor determinado, el sistema asigna automáticamente valores enteros secuenciales empezando con cero, pero cuando se asigna un valor específico, como es el caso de la variable CUATRO=15 entonces el siguiente valor enumerado será de 16. Una variable de tipo enum es útil cuando se manejan datos con una secuencia predeterminada, por ejemplo los días de la semana, y de esta manera se puede manejar una sola variable la cual puede tomar cualquiera de sus valores predeterminados, mismos que pueden estar representados por nombres significativos. El resultado de la ejecución del programa es el siguiente: ![]()
|