¿Qué es un compilador?
Un compilador es un programa que traduce el código fuente escrito en un lenguaje de programación a código máquina, o a otra forma de más bajo nivel como el bytecode, antes de que el programa se ejecute. Después, el programa traducido puede ejecutarse sin el código fuente original.
Actualizado el 24 de septiembre de 2026
- 1print("Hello")
- 2total = 2 + 3
- 3print(total)
- 4print("Done")
Compila una vez y después ejecuta el programa tantas veces como quieras: el contador de ejecuciones sube, el de compilaciones no. Activa la errata y el compilador rechaza el programa entero, así que no se imprime nada.
Guarda este programa en C como hello.c:
#include <stdio.h>
int main(void) {
int price = 4;
printf("Total: %d\n", price * 3);
return 0;
}
Después escribe gcc hello.c -o hello. Durante un momento no pasa nada visible, y luego aparece un archivo nuevo llamado hello junto a tu código fuente. Ese archivo es el resultado del compilador: código máquina que tu procesador puede ejecutar. Borra hello.c y ./hello sigue funcionando, porque todo lo que el programa necesita ya está traducido.
gcc hello.c -o hello
./hello
Total: 12
Cómo funciona un compilador, paso a paso
Un compilador lee el código fuente como texto plano y lo procesa por etapas. Toma la línea total = price * 3:
- Análisis léxico. El texto se divide en tokens, las "palabras" del lenguaje: el nombre
total, el operador=, el nombreprice, el operador*, el número3. Aquí se descartan los espacios y los comentarios. - Análisis sintáctico. Los tokens se organizan en un árbol sintáctico que registra la estructura: una asignación cuyo valor es la multiplicación de
pricepor3. El código que rompe la gramática del lenguaje se detiene aquí con un error de sintaxis. - Análisis semántico. El compilador comprueba el significado: si
priceestá declarado, si los tipos son compatibles, si existe la función a la que se llama. - Optimización. El programa se reescribe para que se ejecute más rápido o use menos memoria sin cambiar lo que hace.
x * 2puede convertirse en una sola instrucción de desplazamiento, y el código que nunca puede ejecutarse se elimina. - Generación de código. El compilador escribe el resultado para un destino: código máquina x86-64 o ARM, o bytecode para una máquina virtual.
En C y C++ hay un paso final, el enlazado, que une tus archivos compilados con el código de las bibliotecas (como printf de la biblioteca estándar de C) en un solo ejecutable. gcc ejecuta el enlazador por ti, por eso parece un único comando.
Python incluye las dos primeras etapas como módulos estándar, así que puedes verlas trabajar con una entrada real:
NAME 'total'
OP '='
NAME 'price'
OP '*'
NUMBER '3'
Assign(
targets=[
Name(id='total', ctx=Store())],
value=BinOp(
left=Name(id='price', ctx=Load()),
op=Mult(),
right=Constant(value=3)))
Ese árbol es con lo que trabaja el resto del compilador. Ya no le importan los espacios ni los saltos de línea, solo la estructura: asignar a total el resultado de multiplicar price por 3.
Tiempo de compilación: errores detectados antes de ejecutar el programa
Como un compilador lee todo el programa antes de que se ejecute ninguna parte, puede rechazar los errores pronto. En este ejemplo no se ejecuta ninguna de las tres líneas print que hay dentro de source, ni siquiera la primera, porque el compilador de Python rechaza el texto antes de que empiece la ejecución:
Rejected before running anything:
'(' was never closed (line 3)
Los compiladores de lenguajes con tipado estático detectan algo más que la sintaxis. Esta línea de C, en un archivo llamado bad.c, es gramaticalmente correcta, pero guarda texto en una variable entera:
int count = "five";
GCC 14 y versiones posteriores se detienen con un error:
bad.c:4:17: error: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
El mismo error en Python solo aparecería al ejecutarse esa línea. Detectarlo en tiempo de compilación es una de las razones por las que los equipos grandes eligen lenguajes compilados y con tipado estático. Aun así, un compilador no puede detectarlo todo: dividir por un número que resulta ser cero, o leer un archivo que no existe, sigue fallando en tiempo de ejecución.
Ejemplos de compiladores
| Compilador | Lee | Genera |
|---|---|---|
| GCC, Clang | C, C++ | Código máquina para x86-64, ARM y otras arquitecturas |
| MSVC (Microsoft Visual C++) | C, C++ | Ejecutables de Windows (.exe, .dll) |
javac | Java | Bytecode de la JVM (archivos .class) |
rustc | Rust | Código máquina |
go build | Go | Un único archivo ejecutable |
tsc | TypeScript | JavaScript |
Dos filas muestran que el "código máquina" no es el único resultado posible. javac genera bytecode que ejecuta la Máquina Virtual de Java, parte del entorno de ejecución de Java. tsc convierte TypeScript en JavaScript, otro lenguaje de alto nivel; un compilador que hace esto suele llamarse transpilador.
El código máquina compilado está ligado a una familia de CPU y a un sistema operativo. Un programa compilado para Windows en x86-64 no funciona en un Mac con un chip Apple de la serie M; hay que compilar el mismo código fuente de nuevo para cada destino.
Compilador o intérprete
Un intérprete ejecuta el código fuente directamente en lugar de generar un archivo de programa aparte, que es como se suelen ejecutar Python y Ruby. La mayoría de las herramientas modernas usan las dos ideas: CPython compila tu archivo a bytecode y después lo interpreta, y la JVM y el motor V8 de JavaScript compilan a código máquina el código que más se usa mientras el programa se ejecuta. La tabla comparativa completa está en la página compilador vs intérprete.
Ideas equivocadas frecuentes
- "Si compila, funciona." Un compilador comprueba que el programa es válido, no que sea correcto. Los errores de lógica y los fallos en tiempo de ejecución, como la división por cero, pasan el filtro.
- "Python no se compila." CPython compila cada archivo a bytecode antes de ejecutarlo. Los archivos
.pycde las carpetas__pycache__son ese bytecode, guardado para los módulos que importa tu programa, de modo que la siguiente ejecución pueda saltarse el paso. - "Un compilador online es un compilador." Los sitios que ejecutan tu código en el navegador lo envían a un servidor que ejecuta toda la cadena de herramientas (compilador, enlazador y el propio programa) y devuelve la salida. El compilador es una pieza de eso.
- "El código compilado funciona en cualquier sitio." Funciona en la CPU y el sistema operativo para los que se compiló. La portabilidad se consigue recompilando, o con una máquina virtual como la JVM.
Qué leer después
La documentación de C muestra un compilador en el uso diario: cómo compilar y ejecutar C recorre el preprocesado, la compilación, el ensamblado y el enlazado con comandos gcc reales. Para ver la otra forma de ejecutar código, lee compilador vs intérprete y después entorno de ejecución para saber qué rodea a un programa una vez que arranca. El curso de C es un buen sitio para practicar con un lenguaje compilado.