Diseño del algoritmo.
Esta etapa es, por mucho, la más importante del proceso de programación, por lo que no es casualidad que sea la primera, ya que a partir de la descripción de un problema al cual se le quiera dar solución a través de un programa estructurado escrito en lenguaje C por ejemplo, se realiza un análisis inicial para identificar:
- Los datos de entrada.
- Los datos de salida.
- El proceso general de solución del problema.
El proceso general de solución deberá ser progresivamente detallado y refinado, de tal forma que dicho proceso, a través de su especificación, constituirá la solución algorítmica inicial para el problema planteado.
La especificación algorítmica debe ser la primera etapa durante el proceso de creación de programas, y es, en más de un sentido, la piedra angular del proceso de programación.
Pruebas al algoritmo.
El algoritmo propuesto en la etapa de diseño del algoritmo, debe ser probado con algunos casos básicos y clave, con la finalidad de determinar la congruencia y efectividad de su solución. Es una mala práctica de programación y de ingeniería de software en general, el posponer las pruebas hasta escribir el programa derivado del algoritmo.
Las pruebas son una parte fundamental para la validación del algoritmo, y están estrechamente relacionadas con el proceso de diseño del algoritmo. Su descripción está fuera de los alcances de este texto, pero el lector debería asegurarse de que se conocen y aplican al menos los conceptos básicos de pruebas de algoritmos.
Transcripción del algoritmo a un lenguaje de programación (generación del código fuente).
Esta etapa es básicamente el proceso de traducción del algoritmo a la sintaxis de un lenguaje de programación específico que, para el caso de los ejemplos utilizados será el lenguaje de programación C.
Sólo en los casos de programas excepcionalmente simples y cuando también se posea un significativo nivel de experiencia, podría iniciarse el proceso en esta etapa. Para la edición del programa en código fuente, se puede usar cualquier editor de texto, siempre que el archivo se guarde como texto simple sin formato, pero el uso de un IDE apropiado se recomienda ampliamente desde esta etapa (
CodeLite,
Code::Blocks o
ZinjaI por ejemplo).
La extensión del archivo con el código fuente debería ser “.c”, ya que algunos compiladores, en función de la extensión del archivo a compilar, procesan un conjuntos de directivas o mecanismos acordes a lo que se espera contenga el archivo. Extensiones como “.c++” o “.cpp” sugieren que el archivo a compilar hace uso de características extendidas del lenguaje C (C++), o hacen que el compilador interprete algunas sentencias del archivo como propias del paradigma de programación orientado a objetos por ejemplo, o que el compilador analice el código en base a otra gramática distinta a la de C, generando así mensajes que pudieran confundir al programador.
También es posible editar archivos que agrupen un conjunto de funciones que parezcan archivos de biblioteca personalizados. Técnicamente no lo son, pero es un estándar de facto el nombrarlos de esta manera.
Compilación.
La etapa de compilación puede resumirse como el
proceso de traducción de un programa escrito en un lenguaje artificial de alto nivel (código fuente), a un conjunto de instrucciones ejecutables por una computadora (programa en código objeto o binario).
El proceso de compilación se escucha simple pero en no lo es. De hecho, el compilador de un lenguaje como C realiza al menos cuatro etapas:
- Pre procesamiento: antes de cualquier cosa, el pre procesador de C ejecuta las directivas de inclusión de archivos (#include), y de definición de tipos (#define), que son las más comunes pero no las únicas. La etapa de pre procesamiento se realiza con la finalidad de definir y establecer las dependencias necesarias indicadas por este tipo de directivas.
- Análisis léxico: es la primera fase del proceso de traducción, y su función es la de descomponer el programa fuente en elementos léxicos o símbolos denominados tokens, los cuales serán utilizados en una etapa posterior durante el proceso de traducción. La salida del analizador léxico es la entrada para el analizador sintáctico.
- Análisis sintáctico: este tipo de análisis se encarga, grosso modo, de verificar que las sentencias contenidas en el archivo fuente correspondan a la gramática del lenguaje C, es decir, que se cumplan con las reglas de estructura, escritura, y orden del lenguaje.
- Análisis semántico: el analizador semántico analiza el significado, sentido o interpretación, así como la intención de los símbolos, elementos léxicos, sentencias y expresiones de la gramática del lenguaje C.
El resultado de estas cuatro etapas es, en el mejor de los casos, la traducción a código objeto del código fuente.
Por otro lado, existe el escenario de la detección de algún error identificado en alguna de las etapas anteriormente mencionadas del proceso de compilación. En éste sentido, pueden identificarse dos tipos de errores:
- Error fatal: este tipo de errores no generan el código objeto derivado del proceso de traducción, debido a la detección de un problema grave durante el análisis del código fuente. Los errores fatales pueden ser por ejemplo: la omisión de un punto y coma, la falta o inconsistencia de paréntesis o delimitadores de bloque, elementos (tokens) no definidos, etc. En el argot computacional, es común denominar a este tipo de errores como: errores en tiempo de compilación.
- Error preventivo: los errores preventivos (warnings) sí producen código objeto, y su carácter es más bien informativo respecto a posibles problemas detectados por el compilador durante el proceso de traducción. La mayoría de este tipo de errores son del tipo semántico, por lo que en este sentido, es responsabilidad del compilador indicar los elementos que le parecieron sospechosos; sin embargo, es responsabilidad del programador validar o no estas advertencias. Algunos de estos errores, si no se corrigen, derivan en problemas durante la ejecución del programa, pero no necesariamente, y se les denomina: errores en tiempo de ejecución. Por otro lado, debe tenerse presente que no todos los errores en tiempo de ejecución son derivados de errores preventivos, la mayoría de los errores en tiempo de ejecución provienen de una lógica incorrecta.
Vinculación.
El vinculador o enlazador (linker) es el responsable de unir las distintas partes que conforman un programa en C.
Tome en cuenta que, como parte del proceso de compilación de la etapa anterior y asumiendo que el código fuente fue traducido con éxito en código objeto, se tienen, hasta ese momento, módulos relacionados pero independientes entre sí.
Tome en cuenta que incluso para el programa más simple, es común hacer uso de funciones, constantes simbólicas, o tipos de datos definidos en alguna de las bibliotecas de funciones que utiliza el lenguaje, por lo que el enlazador es responsable de verificar la correspondencia y existencia de los módulos a los que se hace referencia en el programa fuente, así como de establecer los vínculos o relaciones correspondientes con dichos módulos para constituir y generar un módulo único y funcional, mismo que conformará el conjunto final de instrucciones ejecutables o programa ejecutable.
En resumen, la función del enlazador es la de unir o vincular el código producido por el programador con el código al que se hace referencia en las bibliotecas de funciones, con la finalidad de generar un archivo ejecutable: el programa ejecutable.
Carga y ejecución.
Cada programa ejecutable derivado de un programa en C, cuando se ejecuta o procesa en la computadora recibe la denominación de proceso. Un proceso es una instancia en ejecución de un programa.
Puede decirse en general que un programa y un proceso son conceptos intercambiables indistintamente, pero formalmente obedecen a aspectos diferentes.
- Un programa es un conjunto de instrucciones almacenadas en disco, listas para ser potencialmente ejecutadas como una tarea o aplicación por parte del sistema operativo.
- Un proceso es ese mismo conjunto de instrucciones cargadas ya en la memoria principal de la computadora, mismas que están en posibilidad real de ser procesadas o ejecutadas por el microprocesador. Todas las aplicaciones, tareas o procesos que se están ejecutando en una computadora, deben estar en memoria total o parcialmente.
El proceso responsable de trasladar (cargar) las instrucciones de un programa a la memoria, para que sea susceptible de ser ejecutado como proceso se llama: cargador (loader).
Depuración.
La depuración es propia del proceso de diseño de un programa y es, de hecho, el complemento de la etapa de pruebas, ya que en esta fase, se prueban el conjunto de instrucciones escritas en lenguaje artificial, con la finalidad de verificar y validar que se cumplen los criterios y objetivos para los cuales fue diseñado el programa.
Es común asociar esta etapa a la corrección de errores o problemas (bugs) detectados durante la ejecución del programa y, aunque si bien es cierto que en esta etapa es en donde se tratan de identificar las sentencias que originan algún tipo de problema, no debe perder de vista que las pruebas constituyen una parte fundamental del proceso de diseño y programación, de tal forma que constituyen una parte fundamental de la verificación y validación del programa desarrollado, por lo que realizar las pruebas del algoritmo hasta esta etapa, es una mala práctica de programación.
Esta etapa incluye técnicas básicas de depuración como: la inclusión de puntos de ruptura (break points), ejecución paso a paso (trace), inspección de variables y expresiones (watch), ejecución de módulos completos (step over), y ejecución de módulos paso a paso (step into), entre otros.