C es un lenguaje de programación de propósito general originalmente desarrollado por Dennis Ritchie entre 1969 y 1972 en los Laboratorios Bell, como evolución del anterior lenguaje B, a su vez basado en BCPL.

Al igual que B, es un lenguaje orientado a la implementación de sistemas operativos; concretamente Unix. C es apreciado por la eficiencia del código que produce y es el lenguaje de programación más popular para crear softwares de sistemas y aplicaciones.

Se trata de un lenguaje del tipo datos estáticos, débilmente tipado, que dispone de las estructuras típicas de los lenguajes de alto nivel, pero, a su vez, dispone de construcciones del lenguaje que permiten un control a bajo nivel, lo que lo convierte en un lenguaje de nivel medio. Los compiladores suelen ofrecer extensiones al lenguaje que posibilitan mezclar código en ensamblador con código C o acceder directamente a memoria o dispositivos periféricos.

La primera estandarización del lenguaje C fue en ANSI, con el estándar X3.159-1989. El lenguaje que define este estándar fue conocido vulgarmente como ANSI C. Posteriormente, en 1990, fue ratificado como estándar ISO (ISO/IEC 9899:1990). La adopción de este estándar es muy amplia por lo que, si los programas creados lo siguen, el código es portable entre plataformas y/o arquitecturas.

Filosofía Uno de los objetivos de diseño del lenguaje C es que solo sean necesarias pocas instrucciones en lenguaje máquina para traducir cada elemento del lenguaje, sin que haga falta un soporte intenso en tiempo de ejecución. Es muy posible escribir C a bajo nivel de abstracción; de hecho, C se usó como intermediario entre diferentes lenguajes.

En parte, a causa de ser de relativamente bajo nivel y de tener un modesto conjunto de características, se pueden desarrollar compiladores de C fácilmente. En consecuencia, el lenguaje C está disponible en un amplio abanico de plataformas (más que cualquier otro lenguaje). Además, a pesar de su naturaleza de nivel medio, el lenguaje se desarrolló para incentivar la programación independiente de la máquina. Un programa escrito cumpliendo los estándares e intentando que sea portátil puede compilarse en muchos computadores.

C se desarrolló originalmente (conjuntamente con el sistema operativo Unix, con el que ha estado asociado mucho tiempo) por programadores para programadores. Sin embargo, ha alcanzado una popularidad enorme, y se ha usado en contextos muy alejados de la programación de software de sistema, para la que se diseñó originalmente.

Propiedades Núcleo del lenguaje simple, con funcionalidades añadidas importantes, como funciones matemáticas y de gestión de archivos, proporcionadas por bibliotecas. Es un lenguaje estructurado; tiene estructuras de control y tipos de datos estructurados definidos por el programador a partir de los tipos atómicos típicos y mediante arreglos, estructuras, uniones y punteros, incluidos los que apuntan a una función. En su primera edición no había advertencias sobre asignar a una variable un valor un tipo distinto. Por lo que había un programa llamado lint que detectaba este tipo de errores. Actualmente los compiladores pueden detectar inconsistencias de tipos y otros errores. Usa un lenguaje de preprocesado, el preprocesador de C, para tareas como definir macros e incluir múltiples archivos de código fuente. Acceso a memoria de bajo nivel mediante el uso de punteros. Manejo de Interrupciones mediante la biblioteca signal.h. Un conjunto reducido de palabras clave. El llamado a funciones es por valor. Aunque se pueden pasar punteros a variables para hacer llamados por referencia. Distintos tipos de almacenamiento que permiten un diseño modular. La palabra clave struct permite encapsular variables y funciones. Lenguaje muy eficiente puesto que es posible utilizar sus características de bajo nivel para realizar implementaciones óptimas. Se diseñó como un lenguaje de programación de sistemas portátil. Es muy poco lo que requiere uso de ensamblador, lo que permitió portar Unix y otros sistemas operativos a distintos equipos. Distingue entre mayúsculas y minúsculas, pero conserva su portabilidad en equipos que manejan caracteres de 6 bits, como las computadoras Cyber de CDC que tenían una palabra de 60 bits, (10 caracteres), porque usan gráficos para codificar símbolos especiales. Su compilador de C se ha portado a la mayoría de sistemas. Porque además de que no se requiere codificar en ensamblador, interactúa con los lenguajes especializados YACC y Alex. también escritos en C como parte de Unix. Facilita la programación modular gracias a que cuenta con distintos tipos de almacenamiento de las variables y compilación separada. Esto se logra mediante la inclusión de ficheros cabecera .h mediante la directiva de preprocesador #include. extern sirve para declarar objetos externos que se usarán en el programa pero que no se encuentran en el fichero del programa, por lo que es necesario pasar los nombres de los ficheros como parámetros del enlazador.

Precauciones Los programadores novatos deben tener cuidado con la gestión de la memoria; en C el programador ha de reservar y liberar la memoria explícitamente. En otros lenguajes (como C# o Java) la memoria es gestionada de forma transparente para el programador. Esto alivia la carga de trabajo y evita errores, pero le quita flexibilidad al lenguaje para escribir controladores del hardware.

Por esta razón es muy importante que los recién iniciados adopten buenas prácticas a la hora de escribir en C y manejar la memoria, como por ejemplo un uso intensivo de indentación y conocer a fondo todo lo que implica el manejo de punteros y direcciones de memoria.

Algunas características de las que carece C Recolección de basura nativa, sin embargo se encuentran a tal efecto bibliotecas como la «libre» desarrollada por Sun Microsystems, o el Recolector de basura de Boehm. Soporte para programación orientada a objetos, aunque la implementación original de C++ fue un preprocesador que traducía código fuente de Quer Véase también la librería GObject. Unidadas, aunque GCC tiene esta característica como extensión. Soporte nativo para programación multihilo. Disponible usando librerías como libretad.

Aunque la lista de las características útiles de las que carece C es larga, este factor ha sido importante para su aceptación, porque escribir rápidamente nuevos compiladores para nuevas plataformas, mantiene lo que realmente hace el programa bajo el control directo del programador, y permite implementar la solución más natural para cada plataforma. Esta es la causa de que a menudo C sea más eficiente que otros lenguajes. Típicamente, solo la programación cuidadosa en lenguaje ensamblador produce un código más rápido, pues da control total sobre la máquina, aunque los avances en los compiladores de C y la complejidad creciente de los microprocesadores modernos han reducido gradualmente esta diferencia.

El lenguaje se puede extender mediante bibliotecas y macros. Por ejemplo, la implementación original de C++ consistía en un preprocesador que traducía código fuente C++ a C.

Historia Desarrollo inicial

El desarrollo inicial de C se llevó a cabo en los Laboratorios Bell de AT&T entre 1969 y 1973; según Dennis Ritchie, el periodo más creativo tuvo lugar en 1972. Se le dio el nombre «C» porque muchas de sus características fueron tomadas de un lenguaje anterior llamado «B».

Hay muchas leyendas acerca del origen de C y el sistema operativo con el que está íntimamente relacionado, Unix. Algunas de ellas son: El desarrollo de C fue el resultado del deseo de los programadores de jugar con Space Travel. Habían estado jugando en la unidad central de su compañía, pero debido a su poca capacidad de proceso y al tener que soportar 100 usuarios, Ken Thompson y Dennis Ritchie no tenían suficiente control sobre la nave para evitar colisiones con los asteroides, por ese motivo decidieron portar el juego a un PDP-7 de la oficina que no se utilizaba; pero esa máquina no tenía sistema operativo, así que decidieron escribir uno. Finalmente decidieron portar el sistema operativo del PDP-11 que había en su oficina, pero era muy costoso, pues todo el código estaba escrito en lenguaje ensamblador. Entonces decidieron usar un lenguaje de alto nivel y portátil para que el sistema operativo se pudiera portar fácilmente de un ordenador a otro, consideraron usar B pero carecía de las funcionalidades necesarias para aprovechar algunas características avanzadas del PDP-11 entonces empezaron a crear un nuevo lenguaje: C. La justificación para obtener el ordenador original que se usó para desarrollar Unix fue crear un sistema que automatizase el archivo de patentes. La versión original de Unix se desarrolló en lenguaje ensamblador. Más tarde, el lenguaje C se desarrolló para poder reescribir el sistema operativo.

En 1973, el lenguaje C se había vuelto tan potente que la mayor parte del kernel Unix, originalmente escrito en el lenguaje ensamblador PDP-11, fue reescrita en C. Este fue uno de los primeros núcleos de sistema operativo implementados en un lenguaje distinto al ensamblador. (Algunos casos anteriores son el sistema Multics, escrito en PL/I, y Master Control Program para el B5000 de Burroughs, escrito en ALGOL en 1961).

El C de Kernighan y Ritchie

En 1978, Ritchie y Brian Kernighan publicaron la primera edición de El lenguaje de programación C, también conocido como «La biblia de C». Este libro fue durante años la especificación informal del lenguaje. El lenguaje descrito en este libro recibe habitualmente el nombre de el «C de Kernighan y Ritchie» o simplemente «K&R C» (La segunda edición del libro cubre el estándar ANSI C, descrito más adelante en este artículo).

Kernighan y Ritchie introdujeron las siguientes características al lenguaje:

El tipo de datos struct. El tipo de datos long int. El tipo de datos unsigned int. Los operadores =+ y =- fueron sustituidos por += y -= para eliminar la ambigüedad sintáctica de expresiones como i=-10, que se podría interpretar bien como i =- 10 o bien como i = -10.

El C de Kernighan y Ritchie es el subconjunto más básico del lenguaje que un compilador debe de soportar. Durante muchos años, incluso tras la introducción del ANSI C, fue considerado «el mínimo común denominador» en el que los programadores debían programar cuando deseaban que sus programas fueran transportables, pues no todos los compiladores soportaban completamente ANSI, y el código razonablemente bien escrito en K&R C es también código ANSI C válido.

En las primeras versiones del lenguaje, la definición de funciones se hacía mediante un 'prototipo de función' (function prototype), el cual indicaba al compilador el tipo de retorno de la función. Aunque este método tiene una gran desventaja respecto al nuevo, debido a que no comprueba el número ni el tipo en la lista de argumentos; en otras palabras, es mucho más fácil cometer errores al hacer una llamada a una función con argumentos incorrectos.

Ejemplo del «viejo estilo»: int power(); /* Se podría usar este prototipo para llamar a la función. Simplemente power(); u omitirlo dado que el tipo por default es int */

power(a,b) int a, b; { int n; for (n = 2; b > 0; --b) n *= a; return n; }

Ejemplo de la nueva definición: int power(int a, int b) { for (int n = 1; b > 0; --b) n *= a;

return n; }

(*) Por defecto, el tipo de retorno en C es int, por lo que la declaración entera int power(); podría haberse omitido.

En los años siguientes a la publicación del C de Kernighan y Ritchie, se añadieron al lenguaje muchas características no oficiales, que estaban soportadas por los compiladores de AT&T, entre otros. Algunas de estas características eran:

Funciones void y el tipo de datos void *. Funciones que retornaban tipos de datos struct o union (en lugar de punteros). Asignación de tipos de datos struct. Calificador const, que hace que un objeto sea de solo lectura.