1.5 Secuencia de ejecución de un programa
Desde que es invocado por su entorno (normalmente el Sistema Operativo) hasta
que termina, la ejecución de un programa C++ recorre las siguientes etapas:
§1 Se ejecuta el módulo inicial.
Durante la fase de enlazado de la compilación, el enlazador añade a cualquier
programa C++ un módulo especial, de inicio, que es realmente el punto de
entrada a la ejecución del programa [2]. Este
módulo realiza diversas tareas, entre ellas iniciar todas las variables
estáticas o globales (ver nota), controlar la ejecución de posibles funciones
opcionales de inicio (ver punto siguiente) y finalmente, invocar la función main
( 4.4.4).
Nota: cuando se compila cualquier módulo, en el objeto resultante existe un segmento denominado _INIT_ que contiene una referencia ("Init entry") al constructor de cada objeto global que deba ser inicializado, así como un orden de prioridad. Más tarde, cuando el enlazador construye un ejecutable, estas entradas se agrupan en una tabla, la tabla de inicio ("Init table") que contiene ordenadamente todas las entradas de los constructores de los objetos que existen en los módulos que componen el programa. Finalmente, esta tabla es utilizada por el módulo de inicio cuando el programa es iniciado.
§2 Se ejecutan las funciones de inicio.
Algunos compiladores permiten al programador la opción de que se invoquen determinadas funciones, antes que se realice
la llamada a main. Estas funciones representan tareas preparatorias adicionales,
que queremos realizar antes de que se inicie la ejecución. Esto se consigue con la directiva de inicio
#pragma startup (
4.9.10i).
§3 Se invoca la función main()
Después de lo anterior, el control pasa a una función que debe responder al nombre de
main y le pasa algunos argumentos en base a datos que ha recibido a su vez del Sistema Operativo
( 4.4.4).
Así pues, en ausencia de funciones particulares de inicio, main
representa el punto de la ejecución a partir del cual el programador toma
control de la ejecución. El cuerpo de esta función
representa la ejecución del programa, su "carga útil".
§4 Se ejecutan las funciones de salida.
Algunos compiladores permiten la opción de llamar determinadas funciones antes que se alcance el final del programa, justo
antes de su terminación. Estas funciones, que representan tareas adicionales que queremos realizar antes de que el programa
devuelva el control a su entorno de ejecución. Se establecen con la directiva #pragma exit
( 4.9.10i).
La Librería Estándar C++ también proporciona una función especial: atexit() que permite la opción de ejecutar un
código específico en la terminación (
1.5.1).
§5 Finalización
Un programa C++ puede terminar por varios motivos:
- Se termine la función main(). Bien porque se alcance el
corchete de cierre "}", bien porque se encuentra una
sentencia return; esto último es lo deseable (aunque no
imprescindible), ya que el estándar define que main debe devolver
un int a su entorno de ejecución (
4.4.4).
- Se encuentra una invocación a la función exit(), una función de la
Librería Estándar (
1.5.1).
- Se encuentra una invocación a la función abort(), otra función Librería Estándar
(
1.5.1).
- Se lanza una excepción que no encuentra su manejador ("handler")
correspondiente (
1.6.3 Excepciones imprevistas).
En el apartado
1.5.1
se incluye la descripción de algunas de las funciones relativas a la
terminación de un programa [1].
Hay que recordar que en un programa C++ todos los objetos globales se mantienen activos hasta que se han ejecutado todas las funciones de salida. Las variables locales, incluyendo las declaradas en la función main son destruidas a medida que quedan fuera de ámbito. Al final de un programa C++ Builder el orden de ejecución es como sigue:
- Las funciones de salida son ejecutadas en el mismo orden que fueron insertadas por atexit.
- Las funciones declaradas en #pragma exit son ejecutadas en orden a sus códigos de prioridad.
- Se llama al destructor de variables globales.
Ver algunos comentarios
adicionales sobre un caso concreto:
2.2.6.
[1] Aunque en rigor su descripción debería estar incluida en el capítulo 5 dedicado a la Librería Estándar, mientras no implemente completamente dicha parte en el presente "Libro", mantendremos aquí la descripción de estas funciones.
[2] El Estándar indica que tanto este módulo como el de terminación son dependientes de la implementación (pueden ser diferentes para cada compilador).