¿Qué es C++? Compilador y primer programa
Del código fuente al ejecutable: qué hace el compilador y cómo escribir tu primer programa
C++ es un lenguaje compilado: tu código pasa por preprocesador, compilador y enlazador antes de convertirse en un ejecutable. En esta lección escribes tu primer programa, lo compilas con g++, aprendes a leer los errores y eliges el estándar con -std=c++20.
- Explicar la diferencia entre un lenguaje compilado y uno interpretado
- Compilar y ejecutar un archivo .cpp desde la terminal
- Describir las fases de preprocesado, compilación, ensamblado y enlazado
- Interpretar los primeros errores de compilación y de enlazado
- Seleccionar el estándar con -std=c++20 y comprobarlo con __cplusplus
En esta lección
- ¿Qué es C++?
- ¿Para qué sirve?
- Cómo funciona por dentro: del .cpp al ejecutable
- Sintaxis: el esqueleto de un programa
- Tu primer programa, línea por línea
- Ejemplo intermedio: comprobar el entorno y separar errores
- Caso práctico: un flujo de trabajo completo
- Visualización: qué ocurre al ejecutar el programa
- Estándares: de C++11 a C++23
- Errores comunes (y cómo se leen)
- Buenas prácticas al compilar
- Ejercicios
- Soluciones explicadas
- Resumen
- Evaluación
En Python escribes print("Hola"), pulsas Enter y el resultado aparece. En C++ ese mismo saludo recorre cuatro etapas antes de llegar a la pantalla: preprocesador, compilador, ensamblador y enlazador. Entender esa cadena es la mitad de aprender el lenguaje; la otra mitad es saber leer lo que te dice cuando algo falla.
¿Qué es C++?
C++ es un lenguaje de programación compilado, de tipado estático y de propósito general. Lo creó Bjarne Stroustrup en 1979 como una extensión de C con clases; hoy es un estándar ISO que se revisa cada tres años. Su promesa es doble: control fino sobre la memoria y el rendimiento, sin renunciar a abstracciones de alto nivel.
- Compilado: no hay un intérprete que lea tu archivo en tiempo de ejecución. Un programa traductor convierte el código en instrucciones de máquina y produce un ejecutable.
- Tipado estático: cada variable tiene un tipo conocido antes de ejecutar. El compilador rechaza operaciones que no encajan, como sumar un texto a una fecha.
- Con enlace: tu código no está solo; se une a la biblioteca estándar y a otras bibliotecas en la fase de enlazado.
- Cercano al hardware: puedes trabajar con bytes, direcciones y memoria, algo imposible en Python puro.
- Multiparadigma: admite programación procedural, orientada a objetos y genérica.
La contrapartida es la que notarás primero: más verbosidad y errores que aparecen antes de ejecutar. Ese coste compra velocidad y control.
¿Para qué sirve?
Estos son ámbitos donde C++ no es una curiosidad sino la herramienta habitual:
- Videojuegos y motores gráficos: Unreal Engine está escrito en C++; los bucles de render se miden en milisegundos.
- Sistemas y navegadores: partes de Windows, Chrome, Firefox y LLVM están en C++.
- Computación científica: simulaciones físicas, dinámica molecular y álgebra lineal con Eigen.
- Machine Learning: bibliotecas de entrenamiento e inferencia, y extensiones nativas para Python.
- Sistemas embebidos y robótica: drones, controladores y sensores con memoria limitada.
En este curso lo usarás sobre todo en el cuarto punto: programas que calculan, leen datos y toman decisiones, para entender qué hay debajo de NumPy.
Cómo funciona por dentro: del .cpp al ejecutable
Cuando compilas, no ocurre una sola cosa. El compilador es en realidad una cadena de programas, y cada uno recibe la salida del anterior. La opción -v de g++ te muestra la lista completa si tienes curiosidad.
- Preprocesado: se resuelven las líneas que empiezan por
#;#include <iostream>se sustituye por la cabecera completa. - Compilación: se comprueban sintaxis y tipos y se genera ensamblador. Un error aquí detiene el proceso.
- Ensamblado: se produce código objeto (
.o), con referencias pendientes a funciones externas. - Enlazado: se une tu objeto con la biblioteca estándar. Si falta
main, el error aparece en esta fase.
La diferencia con Python es de momento, no de capacidad. Python traduce a bytecode y ejecuta; C++ produce un binario que el sistema operativo lanza directamente, incluso donde no hay compilador instalado.
Sintaxis: el esqueleto de un programa
Todo programa necesita una función main: es el punto de entrada que el sistema operativo llama. Un archivo mínimo, que compila aunque no haga nada visible, es este:
#include <iostream>
int main() {
return 0;
}Cada pieza tiene una función. #include <iostream> declara los flujos de entrada y salida; sin esa línea, std::cout no existe para el compilador. int main() indica que la función devuelve un entero al sistema. Las llaves delimitan el cuerpo y return 0 comunica que el programa terminó bien.
- Las directivas
#includevan al principio, fuera demain. - Las sentencias terminan en
;. Olvidarlo es el error más frecuente al empezar. - Los bloques usan llaves
{}; la indentación es solo estilo, no sintaxis. - Los nombres de la biblioteca estándar viven en el espacio de nombres
std.
Tu primer programa, línea por línea
Este es el programa completo. Escríbelo en un archivo llamado hola.cpp, no en un editor de texto con formato: la extensión .cpp le dice al compilador qué esperar.
// Mi primer programa en C++
#include <iostream>
int main() {
std::cout << "Hola, mundo" << '\n';
std::cout << "Estoy aprendiendo C++" << '\n';
return 0;
}La primera línea es un comentario: el compilador la ignora. std::cout es el flujo de salida estándar. El operador << envía el valor de la derecha al flujo de la izquierda y devuelve el flujo, y por eso puedes encadenar valores. '\n' es un salto de línea; con comillas dobles sería una cadena de un carácter.
Compílalo y ejecútalo. El nombre del ejecutable lo eliges con -o; si lo omites, g++ escribe a.out.
g++ -std=c++20 -Wall -Wextra -Wpedantic hola.cpp -o hola
./hola-std=c++20 fija el estándar. -Wall y -Wextra activan avisos que en otros lenguajes serían errores silenciosos. -Wpedantic avisa de extensiones no estándar.
Ejemplo intermedio: comprobar el entorno y separar errores
Un programa puede escribir en dos flujos: std::cout para la salida normal y std::cerr para los errores. Se redirigen por separado, algo útil cuando la salida se guarda en un archivo y los errores deben verse en la terminal.
#include <iostream>
int main() {
std::cout << "== Verificación del entorno ==\n";
std::cout << "Estándar: " << __cplusplus << '\n';
std::cout << "Compilador listo\n";
std::cerr << "Aviso: este mensaje va a stderr\n";
return 0;
}La macro __cplusplus contiene el estándar con el que compilas en formato numérico: 201703 para C++17 y 202002 para C++20. Es la forma más rápida de comprobar que -std=c++20 surtió efecto. std::endl inserta un salto y vacía el búfer; '\n' solo inserta el salto.
g++ -std=c++20 -Wall -Wextra entorno.cpp -o entorno
./entorno # todo junto
./entorno 2>/dev/null # solo stdout
./entorno 1>/dev/null # solo stderrCaso práctico: un flujo de trabajo completo
Repite lo que harás cientos de veces: crear una carpeta, compilar con avisos, ejecutar y comprobar el código de salida. El código de salida es el número que main devuelve al sistema operativo; la integración continua lo usa para decidir si un paso falló.
mkdir -p ~/curso-cpp && cd ~/curso-cpp
g++ -std=c++20 -Wall -Wextra -Wpedantic hola.cpp -o hola
./hola
echo $? # 0: terminó sin erroresAhora un programa que termina con un código distinto de cero. No es un capricho: así se comunican los fallos en las herramientas de línea de comandos.
#include <iostream>
int main() {
std::cout << "Terminando con un error simulado\n";
return 3;
}g++ -std=c++20 -Wall -Wextra estado.cpp -o estado
./estado; echo $? # imprime 3El programa se ejecuta completo; el 3 no es un error del compilador, es información para quien lo invocó. return 0 equivale a «todo bien».
Visualización: qué ocurre al ejecutar el programa
La traza siguiente separa dos momentos que suelen confundirse: lo que hace el compilador con el archivo y lo que hace el programa ya compilado. Fíjate en que la salida solo aparece cuando el flujo de ejecución llega a cada std::cout.
#include <iostream>int main() { std::cout << "Paso 1: compilar\n"; std::cout << "Paso 2: enlazar\n"; std::cout << "Paso 3: ejecutar\n"; return 0;}#include <iostream> por la declaración de los flujos. Esto ocurre antes de compilar y no produce salida.—
Avanza paso a paso: observa la línea resaltada, las variables y la salida.
Estándares: de C++11 a C++23
C++ se revisa cada tres años y el nombre corto usa el año del borrador. Elegir estándar cambia qué sintaxis acepta el compilador.
| Estándar | Año | Qué aportó |
|---|---|---|
| C++11 | 2011 | auto, lambdas, nullptr, constexpr, movimiento y std::thread |
| C++14 | 2014 | auto en el retorno, literales binarios, std::make_unique |
| C++17 | 2017 | if constexpr, enlaces estructurados, std::filesystem, std::optional |
| C++20 | 2020 | Conceptos, rangos, módulos, corrutinas, <=> y std::span |
| C++23 | 2023 | std::expected, std::print y subíndices multidimensionales |
Este curso usa C++20 porque es el estándar moderno mejor soportado por g++, clang++ y MSVC. Si compilas sin -std, el valor por defecto puede ser antiguo.
saludo = "Hola, mundo"
print(saludo)#include <iostream>
#include <string>
int main() {
std::string saludo = "Hola, mundo";
std::cout << saludo << '\n';
return 0;
}Python ejecuta el archivo tal cual con el intérprete. C++ necesita dos pasos: compilar para producir un binario y ejecutar ese binario. A cambio, el binario arranca sin analizar el texto del programa cada vez.
Errores comunes (y cómo se leen)
En Python la traza se lee por la última línea. En C++ suele ser al contrario: el primer error es la causa y los siguientes son consecuencias. Corrige el primero, recompila y vuelve a leer.
| Mensaje del compilador | Qué significa | Cómo se arregla |
|---|---|---|
fatal error: iostream: No such file or directory | La cabecera está mal escrita | Revisa la ortografía: #include <iostream> |
use of undeclared identifier 'cout' | Falta #include <iostream> o el prefijo std:: | Incluye la cabecera y escribe std::cout |
expected ';' after expression | Olvidaste el punto y coma de una sentencia | Añádelo; el compilador suele señalar la línea anterior |
Undefined symbols: "_main" (macOS) o undefined reference to 'main' (Linux) | No existe int main() o está mal escrito | Corrige el nombre: main, no mian |
warning: unused variable 'x' | Declaraste algo que no usas | Elimínalo o úsalo: un aviso puede esconder un error |
Los dos últimos mensajes cambian según la plataforma: clang++ en macOS habla de símbolos indefinidos y g++ en Linux de referencias indefinidas. El significado es el mismo: el enlazador no encontró algo que el código prometía.
#include <iostream>
int mian() {
std::cout << "Hola" << std::endl;
return 0;
}#include <iostream>
int main() {
std::cout << "Hola" << std::endl;
return 0;
}El archivo con `mian` compila sin quejas: la función es válida. El error llega al enlazar, porque el punto de entrada debe llamarse `main`. Es un fallo que no es de sintaxis sino de enlazado, y por eso el mensaje no menciona ninguna línea.
Buenas prácticas al compilar
- Compila siempre con
-std=c++20 -Wall -Wextra -Wpedantic: los avisos detectan errores reales. - Pon nombre al ejecutable con
-o;a.outse sobrescribe en cada compilación. - Un archivo, un programa, una función
main. - Compila después de cada cambio pequeño: un error entre 100 líneas es más caro que entre 10.
- Lee el primer error completo; el resto suele desaparecer al corregirlo.
- No ejecutes un binario viejo: si la compilación falló, corres la versión anterior.
Ejercicios
Dos ejercicios para fijar el flujo y uno para completar el esqueleto.
Tu presentación en tres líneas
presentacion.cpp que imprima tu nombre, tu carrera y un objetivo, cada uno en su propia línea. Compílalo con g++ -std=c++20 -Wall -Wextra -Wpedantic y ejecútalo. Después cambia el orden de las líneas y vuelve a compilar: comprueba que la salida cambia en el mismo orden.Pista
Cada línea de salida es un std::cout que termina en un salto de línea. No necesitas variables todavía.
Detective del estándar
estandar.cpp que imprima el valor de __cplusplus. Compílalo dos veces, con -std=c++17 y con -std=c++20, y anota los dos números que aparecen. Después cambia return 0; por return 3; y comprueba con echo $? que el sistema recibe 3.Pista
__cplusplus ya es un número listo para imprimir: no lleva comillas. El código de salida se consulta inmediatamente después de ejecutar.
#include int ( ) { std:: << "Hola desde C++\n"; return ; }
La cabecera va entre ángulos y el flujo de salida vive en `std`.
Soluciones explicadas
En el primer ejercicio, tres std::cout producen tres líneas y hacen visible que el orden de las sentencias es el orden de la salida. Podrías usar un solo std::cout con tres saltos de línea; ambas versiones son correctas, pero la primera se lee mejor cuando cada línea tiene un propósito.
En el segundo, __cplusplus no es una variable tuya: es una macro que el compilador define antes de compilar. Por eso cambia según el flag y no según el contenido del archivo. El return 3 no imprime nada: el 3 sale por echo $?, que lee el estado que el proceso dejó al terminar.
En el ejercicio de completar, las cuatro piezas son obligatorias: sin cabecera no existe std::cout, sin main el enlazador no encuentra el punto de entrada, sin std:: el nombre no se resuelve y sin return la función no cumple su contrato.
Resumen
- C++ es compilado y de tipado estático: el binario se produce antes de ejecutar.
- La cadena de compilación es preprocesador, compilador, ensamblador y enlazador.
maines el punto de entrada obligatorio y devuelve un entero al sistema operativo.std::cout << valorescribe en la salida estándar;'\n'es un salto de línea.std::cerres el flujo de errores y se redirige por separado.- La orden base es
g++ -std=c++20 -Wall -Wextra -Wpedantic archivo.cpp -o programa. - El primer error del compilador suele ser la causa; los demás son consecuencias.
__cplusplusrevela el estándar activo: 202002 para C++20.
Evaluación
¿Qué produce g++ hola.cpp si no indicas la opción -o?
¿En qué fase aparece un error como undefined reference to main?
¿Qué valor imprime __cplusplus al compilar con -std=c++20?
¿Ya lo entendiste?
Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.