En un principio, C nació en los laboratorios Bell de AT&Tcomo un lenguaje de programación de sistemas, y más específicamente de sistemas operativos. En efecto, las primeras versiones de UNIX se implementaron en ensamblador, pero Dennis Ritchie reescribió el código de UNIX ya existente en C, para facilitar su mantenimiento y transportabilidad. Hoy en día sólo una pequeña parte del núcleo de UNIX se sigue escribiendo en ensamblador, estas son, las partes que se comunican íntimamente con el hardware. Este lenguaje está inspirado en el lenguaje B escrito por Ken Thompson en 1970 con intención de decodificar el UNIX, que en la fase de arranque esta escrito en ensamblador, en vistas a su transportabilidad a otras máquinas. B era un lenguaje evolucionado e independiente de la máquina, inspirado en el lenguaje BCPL concedido por Martin Richard en 1967. Luego, en 1972, Dennis Ritchie toma el relevo y modifica el lenguaje B, creando el lenguaje C y reescribiendo el UNIX basándose en dicho lenguaje. La novedad y ventaja comparativa que proporcionó el lenguaje C sobre B en el momento de su creación y desarrollo fue el diseño de tipos y estructuras de datos. Los tipos básicos de datos eran char (carácter), int (entero), float (reales en simple precisión) y double(reales en doble precisión). Posteriormente se le añadieron los tipos short (enteros de longitud menor a la del int), long (enteros de longitud mayor a la del int) y enumeraciones. Los tipos estructurados básicos de C son las estructuras, las uniones y los arrays. Estos permiten la definición y declaración de tipos derivados de mayor complejidad.
Las instrucciones de control de flujo de C son las habituales de la programación estructurada:if, for, while, swith-case, todas incluidas en su predecesor BCPL. El lenguaje C incluye también punteros y funciones. Los argumentos de las funciones se pasan por valor, esto es copiando su valor, lo cual hace que no se modifiquen los valores de los argumentos en la llamada.
Cuando se desea modificar los argumentos en la llamada, éstos se pasan por referencia, es decir, se pasan las direcciones de los argumentos. Por otra parte, cualquier función puede ser llamada recursivamente.
Una de las peculiaridades y más grandes ventajas de C es su riqueza de operadores. Puede decirse que prácticamente dispone de un operador para cada una de las posibles operaciones en código máquina. Sin embargo, hay además toda una serie de operaciones posibles de realizar con el lenguaje C pero que no están incluidas en el compilador propiamente dicho, si no que C las realiza a través de un preprocesador el cual actúa justo antes de cada compilación. Las dos operaciones más importantes en este ámbito son #define (directriz de sustitución simbólica o de definición) e #include (directriz de inclusión en el fichero fuente).
Sin embargo, el lenguaje C, que ha sido pensado para ser altamente transportable y para programar lo improgramable, presenta inconvenientes al igual que todos los otros lenguajes:
- Carece de instrucciones de entrada/salida de instrucciones para manejo de cadenas de caracteres, con lo que este trabajo queda para la librería de rutinas, con la consiguiente pérdida de transportabilidad.
- La excesiva libertad en la escritura de los programas puede llevar a errores en la programación que, por ser correctos sintácticamente no se detectan a simple vista.
- Por otra parte, las precedencias de los operadores convierten a veces las expresiones en pequeños rompecabezas.
Los detractores de C resaltan que este lenguaje es de nivel medio. Esto no significa que sea más complejo que uno de bajo nivel como el ensamblador, ni tampoco menos evolucionado y en definitiva peor diseñado que uno de alto nivel, como Pascal o su derivado Ada. El “nivel” de un lenguaje no viene dado por su dificultad o su utilidad, si no que por las operaciones que se puedan especificar en él. Se dice que C es un lenguaje de nivel medio porque “aúna” elementos de los lenguajes de alto nivel con las posibilidades que ofrece el lenguaje ensamblador.
En estos lenguajes de alto nivel tiene especial importancia el concepto de tipo de dato, que define el conjunto de valores que puede tomar una variable, y el conjunto de operaciones que se pueden efectuar sobre ella. Algunos tipos son fácilmente comprensibles intuitivamente, como los enteros o los reales, pero otros son más oscuros, como el tipo de datos vacío (void) de C. Todos los lenguajes de alto nivel controlan el uso de los distintos tipos de datos; o sea, ciertas operaciones sólo se pueden realizar sobre ciertos tipos; esto se denomina tipificación. Sin embargo, este control puede efectuarse rígidamente, como en Pascal o Ada, o ser aplicado menos estrictamente, como en C; por esto, se dice que C es un lenguaje débilmente tipificado. Esto conlleva que en C se pueda realizar cualquier transformación de datos, la mayoría incluso de forma implícita. Por ejemplo, el paso del tipo carácter al tipo entero se realiza implícitamente en cualquier expresión de C. Otra característica que C comparte con los otros lenguajes de alto nivel es la posibilidad de crear nuevos tipos de datos a partir de los ya existentes.
Por otro lado, C hereda capacidades del lenguaje ensamblador como la manipulación directa de mapas de bits, punteros, y otros tipos que usa el hardware internamente. Es por este motivo que C está particularmente bien adaptado a la programación de sistemas.
Sin embargo, a pesar de combinar muchas de las ventajas de los lenguajes de alto y bajo nivel, C hereda también algunos de sus problemas. La mayoría de estas dificultades provienen del hecho de que C es un lenguaje pensado por y para programadores; su diseño considera la eficiencia del programa final más que la facilidad de desarrollo. De hecho, es un lenguaje que se lee difícilmente, al permitir “expresiones idiomáticas”particulares, que fomentan la escritura de código difícilmente comprensible para los demás. Además, este lenguaje no implementa ningún tipo de comprobación de errores en tiempo de ejecución; o sea, el compilador asume que aquello que se le pide, aunque parezca extraño, procede de un programador experimentado, que sabe exactamente lo que quiere; esto conlleva que ciertas tareas que en otros lenguajes de más alto nivel son largas se puedan realizar rápidamente en C, pero también que ciertos errores comunes que son localizados en otros lenguajes en tiempo de compilación puedan quedar ocultos durante mucho tiempo en programa en C. En definitiva, se puede decir que C proporciona un gran control al desarrollador sobre cada aspecto de su programa, pero éste debe ser manejado cuidadosamente.
No hay comentarios:
Publicar un comentario