Resumen
Esta clase explica qué es un programa y qué hace un compilador: la máquina solo ejecuta operaciones elementales sobre números en memoria, y el código fuente debe traducirse a código de máquina antes de ejecutarse. Recorre con un programa de dos archivos las tres etapas de esa traducción en C++ (preprocesado, compilación y enlace), y distingue lo que ocurre al compilar de lo que ocurre al ejecutar, con un error de cada clase. Compara los lenguajes compilados con los interpretados, resume la historia de C++ hasta las normas C++23 y C++26, y precisa qué C++ enseña este curso.
Objetivos de aprendizaje
- Explicar, con un esquema, el recorrido de un archivo fuente hasta un ejecutable: preprocesado, compilación y enlace, con lo que entra y lo que sale de cada etapa.
- Clasificar un suceso como propio de la compilación, del enlace o de la ejecución, como un error de sintaxis, la falta de una función o una división por cero.
- Comparar un lenguaje compilado con uno interpretado según el momento en que se detectan los errores y lo que el programador ve de la máquina.
- Situar en el tiempo las normas del lenguaje y explicar por qué el curso usa C++23.
Qué es un programa
Un programa es una sucesión de instrucciones que una máquina puede ejecutar para transformar unos datos en unos resultados. En la clase anterior, Del problema al algoritmo, se vio que antes del programa está el algoritmo, el método que resuelve el problema, escrito para que lo siga una persona. El programa es ese mismo método escrito para una máquina, que no entiende frases ni intenciones, sino órdenes elementales: copiar un número de un lugar de la memoria a otro, sumar dos números, compararlos, saltar a otra instrucción según el resultado.
La memoria del computador es una larga fila de casillas numeradas, cada una con un número de 0 a 255 (un byte). Todo lo que la máquina maneja está allí codificado como números: los datos y también las propias instrucciones. Si esto es así, un programa ejecutable es una sucesión de números que el procesador interpreta como órdenes, el código de máquina, y depende del procesador: los de la familia x86-64, comunes en los computadores de escritorio, y los ARM, comunes en los teléfonos y en los Mac recientes, no entienden los mismos números.
Nadie escribe hoy en código de máquina. Se escribe en un lenguaje de alto nivel, como C++, cuyas instrucciones se parecen a la notación matemática, en un archivo de texto llamado código fuente (o simplemente fuente). De ello se sigue la necesidad de un traductor que produzca, a partir de la fuente, el código de máquina equivalente: en C++, el compilador.
Este es un programa completo en C++. No hace falta entenderlo todavía: cada una de sus líneas se explicará en la clase 1.5. Basta ver que es texto, que puede leerse, y que debajo aparece lo que escribió al ejecutarse.
// Se explicará línea por línea en la clase 1.5.#include <print>int main(){ std::println("Hola, mundo"); std::println("2 + 3 = {}", 2 + 3);}Hola, mundo2 + 3 = 5Para ver el otro extremo de la traducción, considérese una función que solo suma dos enteros (las funciones se estudiarán en la unidad 5). No es un programa completo, porque le falta main, el punto donde comienza la ejecución, pero el compilador puede traducirla por sí sola.
int add(int a, int b){ return a + b;}El programa objdump muestra el código de máquina que GCC 15 produjo para ella en un computador x86-64 con Linux: en cada línea, la posición de la instrucción, sus bytes en hexadecimal y su nombre legible.
$ g++ -std=c++23 -O1 -c add.cpp$ objdump -d add.o0000000000000000 <_Z3addii>: 0: f3 0f 1e fa endbr64 4: 8d 04 37 lea (%rdi,%rsi,1),%eax 7: c3 retLa suma entera se redujo a ocho bytes. La primera instrucción, endbr64, es una marca de seguridad que no calcula nada; la segunda, lea, suma los dos números que la función recibió en dos registros del procesador (%rdi y %rsi) y deja el resultado en un tercero (%eax); la tercera, ret, vuelve al punto desde donde se llamó a la función. El nombre _Z3addii es la forma en que el compilador codifica «función add con dos parámetros int».
Dos observaciones se siguen del ejemplo. Primera: el código de máquina no conserva los nombres a y b, ni la sangría, ni los comentarios; todo eso existía para quien lee la fuente, y el compilador lo usó para decidir qué instrucciones escribir. Segunda: lo que el programador de C++ escribe se traduce en pocas instrucciones y sin intermediarios; esa cercanía a la máquina es la razón de la eficiencia de C++ y, como se verá en el curso, también de algunos de sus peligros.
Cargando el contenido…