Tabla de fichas Indice del Tema 0006
0001 0002 0003 0004 0005 0006 0007 0008

CONCEPTO DE CONTROL DE FLUJO.






¿Qué es el control de flujo?
Retomando nuestra visión anterior de lo que un programa de ordenador, se recordará que se trata de una colección de instrucciones de lenguaje máquina. Cuando se va a ejecutar una instrucción, el contador de programa (un registro interno de la UCP) indica de qué posición de memoria es preciso leerla, y la instrucción es leída, decodificada y ejecutada.La longitud de estas instrucciones, esto es, la cantidad de espacio que ocupa cada una en memoria, no es constante en general: depende de la instrucción, y también de las direcciones y datos que la acompañan. El contador de programa dispone de la circuitería necesaria para calcular automáticamente la posición de la próxima instrucción que debe ejecutarse, y de esto trata precisamente el control de flujo: de determinar el orden concreto en que se ejecutan las instrucciones de que consta el programa. Podría hacerse por orden ascedente de instrucciones, o por orden descendente, o quizá convenga ejecutar una colección de instrucciones muchas veces, calculando valores y modificando alguno de ellos para saber cuándo debe finalizar esa serie de repeticiones. El orden preciso depende del algoritmo que se quiere implementar con ese programa.

Flujo secuencial
En un programa secuencial, el contador de programa se limita a ejecutar la próxima instrucción que hay que ejecutar, teniendo en cuenta la longitud de la instrucción anterior, pero sin saltar instrucciones intermedias. Este tipo de programas es prácticamente inexistente: todos los programas hacen uso de llamadas a funciones, como mínimo, y esto supone un flujo decididamente no secuencial, como se verá.
Con todo, el flujo secuencial es el más rápido posible, y ciertos segmentos de código, especialmente los relacionados con cálculo intensivo, son secuenciales por esta razón. Sin meternos ahora en profundidades, puede obtenerse una mejora de rendimiento sustituyendo una ejecución repetitiva por una secuencial, en caso de que sea aceptable el mayor coste de memoria que supone "desarrollar" el bloque de instrucciones repetidas.

Flujo alternativo
Los procesadores admiten perfectamente una situación dicotómica, en la cual sea preciso ejecutar o bien un segmento de código o bien otro distinto. Desde el punto de vista del lenguaje máquina, existen instrucciones que producen un "salto", insertando directamente en el contador de programa la dirección de una instrucción que puede estar situada en alguna zona de memoria alejada, en lugar de tratarse de la próxima instrucción por orden secuencial. Estas instrucciones pueden ser incondicionales (recuérdese la sentencia goto), forzando el salto de forma obligatoria, y también pueden ser (este es el caso del flujo de control alternativo) condicionales. Esto último significa que el salto se producirá si es verdadero el resultado de evaluar una expresión. Se puede incluso, preparar una combinación de saltos condicionales e incondicionales, con objeto de hacer que se ejecute un bloque de código si resulta ser cierta una expresión, u otro bloque de código distinto si la expresión resultar ser falsa. Este tipo de flujo se consigue, como decimos, calculando la dirección de la próxima instrucción

Flujo selectivo
Hay ocasiones en que el algoritmo empleado para realizar una tarea consta de una cierta cantidad de casos, que dependen de forma arbitraria de un cierto valor entero. Por ejemplo, el cálculo de la desgravación en un programa de hacienda depende del estado civiL de la persona:soltero, casado, viudo, etc. Se podría calcular la desgravación mediante una programa de flujo alternativo, pero esto exigiría ir comprobando sucesivamente si un valor coincidía o no con el bloque de código en que se trata el caso correspondiente. Existe un método consistente en calcular la dirección a la que debe efectuarse el salto, tomando como base el número que especifica el caso de interés. Por así decir, podemos tener una lista de direcciones a las que es preciso saltar, y emplear el número identificativo del caso como índice dentro de esa lista. Este tipo de flujo se llama selectivo, y es más sencillo que emplear un complejo flujo alternativo cuando el número de casos a tener en cuenta se vuelve elevado.

Flujo repetitivo
¿Qué sucede si al final de un segmento de código se pone un salto incondicional al principio del mismo? Claramente, las instrucciones de que consta el segmento de código se repetirán una y otra vez, hasta que algún proceso de mayor prioridad interrumpa la ejecución de ese bucle infinito. Esto tiene dudosa utilidad. Pero supongamos que al final del bucle se pone una instrucción que incrementa el valor de una variable, y después un salto condicional que salte al principio del segmento de código sólo si el valor de la variable es menor que un cierto valor. Entonces habremos conseguido ejecutar el segmento un determinado número de veces, y no para siempre. De este modo, el bloque de sentencias repetidas se ejecutará al menos una vez.
Otra posibilidad es poner el salto condicional al principio, y el incondicional al final, indicando al salto condicional que debe transferir el flujo a la sentencia inmediatamente siguiente al salto incondicional cuando no resulte falsa la expresión del primer salto. Entonces quizá no entremos nunca en el bloque de sentencias repetidas.
En estos dos casos, hemos conseguido repetir un conjunto de sentencias un cierto número de veces... y si complicamos suficientemente la expresión del salto condicional, podremos hacer que ese bloque de sentencias se ejecute mientras sea cierta una situación compleja, o hasta que se produzca una situación determinada. Esto es lo que se denomina flujo repetitivo.

Llamada a una función
La idea de los saltos (condicionales o incondicionales) conlleva proseguir la ejecución una vez ejecutado el bloque de código al que nos lleva el salto. Los procesadores han hecho un arte de este tipo de flujo, y proporcionan instrucciones que almacenan automáticamente la dirección a la que hay que volver una vez concluido el segmento de código al que nos lleva el salto. El mecanismo es sencillo: cuando se llega al final de ese código, el programador inserta una instrucción que dice, simplemente, "volver". ¿Dónde hay que volver? A una dirección que se guarda en memoria (en la pila de la computadora) antes de efectuar el salto. De este modo, resulta muy cómodo ejecutar bloques concretos de código para luego proseguir nuestra ejecución: estos bloques de código con una instrucción de vuelta al final reciben el nombre de funciones, subrutinas o subprogramas. Los lenguajes de alto nivel añaden características muy potentes (el llamado espacio de nombres y las reglas de ámbito) a las llamadas a función, al extremo que se puede decir que un programa es, normalmente, una colección de llamadas a funciones.
Evidentemente, aun cuando el programa sea una colección de funciones, tiene que existir una función que corresponda al punto del código en que empieza a ejecutarse el programa. Esa función se llama función o programa principal; es la primera en ejecutarse (cuando arranca el programa) y la última en finalizar (cuando termina el programa). Todo programa poseerá una función principal (llamada main()), y una sola.