AulaML Python · C++
C++ principiante · 35 min · Fundamentos de C++

¿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.

Lección 1 de 3 del módulo
Al terminar esta lección podrás
  • 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
  1. ¿Qué es C++?
  2. ¿Para qué sirve?
  3. Cómo funciona por dentro: del .cpp al ejecutable
  4. Sintaxis: el esqueleto de un programa
  5. Tu primer programa, línea por línea
  6. Ejemplo intermedio: comprobar el entorno y separar errores
  7. Caso práctico: un flujo de trabajo completo
  8. Visualización: qué ocurre al ejecutar el programa
  9. Estándares: de C++11 a C++23
  10. Errores comunes (y cómo se leen)
  11. Buenas prácticas al compilar
  12. Ejercicios
  13. Soluciones explicadas
  14. Resumen
  15. 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.

  1. Preprocesado: se resuelven las líneas que empiezan por #; #include <iostream> se sustituye por la cabecera completa.
  2. Compilación: se comprueban sintaxis y tipos y se genera ensamblador. Un error aquí detiene el proceso.
  3. Ensamblado: se produce código objeto (.o), con referencias pendientes a funciones externas.
  4. 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:

CPP minimo.cpp
#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 #include van al principio, fuera de main.
  • 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.

CPP hola.cpp
// 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.

SHELL Compilar y ejecutar
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.

CPP entorno.cpp
#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.

SHELL Tres formas de mirar la misma ejecución
g++ -std=c++20 -Wall -Wextra entorno.cpp -o entorno
./entorno                 # todo junto
./entorno 2>/dev/null     # solo stdout
./entorno 1>/dev/null     # solo stderr

Caso 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ó.

SHELL Ciclo completo en la terminal
mkdir -p ~/curso-cpp && cd ~/curso-cpp
g++ -std=c++20 -Wall -Wextra -Wpedantic hola.cpp -o hola
./hola
echo $?      # 0: terminó sin errores

Ahora 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.

CPP estado.cpp
#include <iostream>

int main() {
    std::cout << "Terminando con un error simulado\n";
    return 3;
}
SHELL El código de salida no se imprime solo
g++ -std=c++20 -Wall -Wextra estado.cpp -o estado
./estado; echo $?     # imprime 3

El 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.

Ejecución visual ·De la compilación a la ejecución
1 / 6
1 #include <iostream>
2
3 int main() {
4 std::cout << "Paso 1: compilar\n";
5 std::cout << "Paso 2: enlazar\n";
6 std::cout << "Paso 3: ejecutar\n";
7 return 0;
8 }
El preprocesador sustituye #include <iostream> por la declaración de los flujos. Esto ocurre antes de compilar y no produce salida.
Variables
fase = preprocesado
código de salida = —
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ándarAñoQué aportó
C++112011auto, lambdas, nullptr, constexpr, movimiento y std::thread
C++142014auto en el retorno, literales binarios, std::make_unique
C++172017if constexpr, enlaces estructurados, std::filesystem, std::optional
C++202020Conceptos, rangos, módulos, corrutinas, <=> y std::span
C++232023std::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.

Ejecutar el mismo saludo
Python
PYTHON saludo.py
saludo = "Hola, mundo"
print(saludo)
C++
CPP saludo.cpp
#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 compiladorQué significaCómo se arregla
fatal error: iostream: No such file or directoryLa cabecera está mal escritaRevisa 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 expressionOlvidaste el punto y coma de una sentenciaAñá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 escritoCorrige el nombre: main, no mian
warning: unused variable 'x'Declaraste algo que no usasElimí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.

Compilar no es lo mismo que ejecutar
Incorrecto
PYTHON Enlaza, pero falla
#include <iostream>

int mian() {
    std::cout << "Hola" << std::endl;
    return 0;
}
Correcto
PYTHON Correcto
#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.out se 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.

Ejercicio 1

Tu presentación en tres líneas

Crea 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.

Ejercicio 2

Detective del estándar

Escribe 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.

Completar código Completa el esqueleto
#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.
  • main es el punto de entrada obligatorio y devuelve un entero al sistema operativo.
  • std::cout << valor escribe en la salida estándar; '\n' es un salto de línea.
  • std::cerr es 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.
  • __cplusplus revela el estándar activo: 202002 para C++20.

Evaluación

Evaluación 1

¿Qué produce g++ hola.cpp si no indicas la opción -o?

Evaluación 2

¿En qué fase aparece un error como undefined reference to main?

Evaluación 3

¿Qué valor imprime __cplusplus al compilar con -std=c++20?

Tus notas

¿Ya lo entendiste?

Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.