C respondió a un problema concreto de los años setenta: ¿cómo escribir
un sistema operativo próximo al hardware para seguir siendo eficiente
sin rehacerlo casi por completo con cada ordenador?
Dennis Ritchie desarrolló C en Bell Labs
dentro de Unix. El lenguaje no intentaba ocultar la máquina. Ofrecía
pocas abstracciones —tipos, funciones, estructuras y punteros—
traducibles eficientemente en varias arquitecturas. Ese compromiso
explica su difusión y los errores de memoria que lenguajes recientes
intentan impedir.
Antes de C: BCPL y B
En los años sesenta, el software de sistemas se escribía sobre todo en
ensamblador. Permitía controlar el procesador, pero cada arquitectura
tenía instrucciones propias. Portar un programa solía exigir reescribir
gran parte.
Martin Richards diseñó BCPL en 1967 como lenguaje compacto para
compiladores y sistemas. Ken Thompson
derivó B para el primer Unix. B simplificaba el trabajo, pero su
modelo esencialmente sin tipos estaba pensado para máquinas organizadas
en palabras.
El PDP-11 podía direccionar bytes y manipular distintos tamaños. Ritchie
añadió tipos, mejoró matrices y estructuras y transformó gradualmente
«New B» en C entre 1971 y 1973.
Un lenguaje moldeado por Unix
C no se diseñó en papel para aplicarlo después. Lenguaje y sistema
avanzaron juntos. Las necesidades del núcleo impulsaron la
representación de direcciones, caracteres, bloques de memoria y
estructuras con poco coste.
Un puntero contiene una dirección. Permite recorrer una matriz,
construir una lista enlazada o acceder a un dispositivo. No garantiza
que sea válida. El programa puede leer fuera de límites, usar memoria
liberada o interpretar bytes con un tipo incorrecto.
El lenguaje deja detalles a la implementación: tamaño de enteros, orden
de bytes o alineación. El código portable debe depender de las garantías
de C, no de particularidades observadas en una máquina.
La reescritura de Unix cambió el alcance
En 1973, la mayor parte del núcleo Unix se reescribió en C. Algunas
porciones dependientes del hardware siguieron en ensamblador, pero el
grueso podía recompilarse para otra arquitectura.
Eso no hizo portable automáticamente todo programa. Controladores e
hipótesis materiales requerían adaptación. Sin embargo, demostró que un
sistema operativo eficiente podía expresarse en un lenguaje superior sin
quedar preso de un procesador.
Unix se difundió por universidades con su código y herramientas. Los
estudiantes aprendieron sistema y lenguaje, desarrollaron programas y
llevaron estas prácticas a la industria. C se benefició de Unix; Unix
fue más adaptable gracias a C.
Sintaxis pequeña, biblioteca esencial
C ofrece pocas construcciones integradas. Entrada y salida, cadenas y
asignación dinámica proceden sobre todo de bibliotecas. Así mantiene un
núcleo compacto e implementable en entornos diversos.
La biblioteca estándar establece un contrato indispensable. Una función
como fopen evita conocer la interfaz exacta del sistema para abrir
archivos. La portabilidad depende de lenguaje, compilador y biblioteca
compatible.
La compilación suele producir código nativo. C no impone máquina virtual
ni recolector. El programador controla la vida de las asignaciones,
logrando consumos previsibles a cambio de mayor responsabilidad.
De K&R C a la norma internacional
En 1978, Brian Kernighan y Dennis
Ritchie publicaron The C Programming Language. Describía el lenguaje
con suficiente precisión para ser referencia de hecho; esa variante
suele llamarse K&R C.
La multiplicación de compiladores reveló divergencias. Un comité ANSI
comenzó en 1983 a definir una norma. C89 formalizó lenguaje y
biblioteca, e ISO la adoptó en 1990.
Las revisiones posteriores añadieron con prudencia tipos, concurrencia y
aclaraciones. La compatibilidad limita la evolución porque enormes bases
e interfaces dependen del comportamiento histórico.
Por qué C influyó en tantos lenguajes
C++ partió directamente de C para añadir
abstracciones. Objective-C le asoció objetos inspirados en Smalltalk.
Java, JavaScript, C# y Go tomaron parte de su sintaxis sin conservar la
memoria.
La sintaxis no debe ocultar contratos distintos. Java protege accesos
mediante máquina virtual. Rust verifica duraciones mediante tipos. Go
usa recolector. Cada uno responde a los costes del control directo de C.
C sigue siendo interfaz común en sistemas, bibliotecas y entornos
integrados. Incluso lenguajes con memoria segura se comunican a menudo
mediante API en C.
Los límites de confiar en quien programa
La norma define comportamientos indefinidos: tras ciertas
infracciones no impone resultado. El compilador puede optimizar
suponiendo que no ocurren. Esta libertad favorece el rendimiento, pero
vuelve imprevisibles algunos errores.
Desbordamientos y errores de duración causaron numerosas
vulnerabilidades. Compiladores, análisis estático, protecciones y reglas
reducen el riesgo sin eliminarlo. C sigue siendo relevante cuando
control y compatibilidad son esenciales, pero no es la opción
predeterminada para todo.
Por qué C sigue importando
C estableció un nivel duradero entre ensamblador y software de alto
nivel. Describe operaciones próximas al hardware con una notación
compartida por arquitecturas.
Su historia enseña que una abstracción exitosa no tiene que ocultar
todos los costes; puede hacerlos manejables. El precio es una disciplina
que C apenas impone y que deben aportar equipos, herramientas y normas.
Cronología
- 1967: Martin Richards presenta BCPL.
- 1969–1970: Ken Thompson desarrolla B para Unix.
- 1971–1972: Dennis Ritchie transforma B en C en el PDP-11.
- 1973: gran parte del núcleo Unix se reescribe en C.
- 1978: se publica The C Programming Language.
- 1983: comienza el trabajo de ANSI X3J11.
- 1989: se publica la norma ANSI C.
- 1990: C se convierte en norma ISO.
- 1999: C99 añade tipos y herramientas numéricas.
- 2011: C11 introduce un modelo de memoria para concurrencia.
- Hoy: C sigue siendo central en sistemas, software integrado e
interfaces.
Preguntas frecuentes
¿Creó Dennis Ritchie C él solo?
Fue su principal diseñador, pero C nació en el entorno colectivo de Bell
Labs al contacto con B, Unix, usuarios y compiladores.
¿Es C portable por naturaleza?
Facilita la portabilidad, pero un programa puede depender de hardware o
extensiones. La portabilidad real exige respetar la norma y aislar
código específico.
¿En qué se diferencian C y C++?
C++ deriva de C y añade clases, templates, sobrecarga y recursos
deterministas. Hoy tienen normas distintas y compatibilidad incompleta.
¿Por qué C no tiene recolector de basura?
Su diseño favorece un entorno reducido y control explícito. Una
implementación puede añadir un recolector, pero la norma no lo exige.
¿Sigue siendo C una buena opción para empezar?
Enseña representación de datos y memoria, pero expone pronto riesgos
complejos. Depende del objetivo pedagógico y del dominio.
¿Sustituirán a C lenguajes más seguros?
Algunos proyectos eligen Rust u otros cuando prima la seguridad. La
magnitud del código, herramientas e interfaces de C garantiza una larga
coexistencia.