Contenido

Por qué C mola

No he podido evitar darme cuenta de que se me había pasado escribir el artículo del lenguaje que quizá más domino. Así que tenía que arreglarlo :D

C es un lenguaje antiguo. Se escribió con un objetivo muy concreto: la creación de sistemas operativos; y aún más concretamente, para la creación de Unix. No solo se ideó antes de que existieran los patrones de programación, sino que ha sido gracias a C que muchos de éstos han sido inventados.

Ansi C

Por qué C mola

Velocidad

Por mucho que lo intentéis, no conseguiréis mejorar la velocidad de un programa C compilado y optimizado con ningún lenguaje interpretado. Un programa C siempre será entre 10 y 100 veces más rápido.

Eso es algo que saben perfectamente los creadores de lenguajes interpretados. En Python, las librerías más usadas se han reprogramado en C para mejorar su eficiencia. El propio intérprete Python está escrito en C.

Compilado

Los compiladores suelen utilizar técnicas de optimización que aumentan la velocidad de ejecución del programa, aunque en ocasiones pueden incrementar su tamaño. Estas técnicas pueden ser locales o globales, y permiten que el programador se centre en escribir código legible, ya que será el compilador quien realice estas mejoras a posteriori.

Fuertemente tipado

C es fuertemente tipado, por lo que podemos ahorrarnos muchas comprobaciones a lo largo de nuestro programa.

Acceso directo a memoria

El acceso a memoria es directo, por lo que podemos hacer cosas realmente interesantes, como copiar grandes bloques de memoria a otra posición; cambiar un puntero, lo que producirá un cambio en todos los siguientes accesos; recorrerlos, …

Si se puede hacer, se puede hacer en C

Cualquier cosa que se pueda programar, se puede hacer en C de forma eficiente. El problema puede ser el tiempo que lleve programarlo, pero se puede hacer.

TADs

La diferencia entre un programador bueno y uno malo en C suelen ser los TADs (Tipos Abstractos de Datos). Es el equivalente a los objetos de otros lenguajes. Permiten embeber funcionalidad en una sola variable y, cuando es necesario, se puede ocultar el contenido de ésta mediante variables opacas.

Por qué C no mola

Espacio de nombres único

Sin duda, la peor característica de C es que no dispone de espacios de nombres. Si le añadimos que no tiene objetos, el resultado es nombres de funciones terriblemente largos.

Páginas de códigos

C se inventó en una época en la que la memoria era cara, carísima. Por lo tanto no estaban para derrochar espacio pensando en las letras raras de cada idioma ni de hacerlo ampliable: la Ñ española, el símbolo del euro, caracteres rusos, chinos, árabes,… Por eso se centraron en la lengua inglesa y describieron 256 caracteres, que podían direccionarse con un único byte. Esto es lo que se conoce como código ASCII.

Como las multinacionales, en concreto IBM, creían que siendo incompatibles se aseguraban la lealtad de sus clientes, decidieron crear otra distinta, que consistía en repartir de forma diferente los mismos 256 caracteres. Esto es lo que se conoce como código EBCDIC.

Después se dieron cuenta que cada idioma tiene sus peculiaridades, así que decidieron que ninguna persona iba a necesitar un ordenador en un idioma para escribir en otro idioma, y reutilizaron algunos símbolos, creando distintas páginas de códigos ASCII y sus homólogos EBCDIC.

Para complicarlo más, los ficheros no tienen ninguna característica que indiquen en qué página de códigos se encuentran escritos (salvo en AS400, que sí dispone de esta propiedad), así que… Bueno, suerte con ellos.

C no tiene soporte para páginas de códigos multibyte. Es necesario utilizar librerías externas para este tipo de operaciones.

Gestión de memoria

La gestión de memoria es algo que recae en el programador. Aunque en ocasiones es algo bueno, en la mayoría de las veces puede producir leaks de memoria, buffer overflows, y otro tipo de accesos a memoria fuera de tiesto.

Goto

Dado que no hay excepciones, algunos programadores utilizan el goto de la muerte para saltar al final de las funciones y asegurar la liberación de la memoria. Éste es un “buen uso” del goto, si no sabes hacerlo mejor.

Yo siempre digo que el goto es una herramienta más y que es muy útil cuando tienes una función de 500 líneas de código. En estos casos, el goto no es tu mayor problema.

Strtok

La instrucción strtok es la mancha negra en un lenguaje muy bien diseñado. La idea de esta función es permitir un párser de lenguajes de forma sencilla.

El problema es que la instrucción tiene estado, y resulta terriblemente sencillo anidar llamadas a la función, que provocarán lecturas incorrectas.

Se ganó la fama el goto, pero puedo aseguraros que el mayor enemigo del programador es el strtok.

Casting

Cuando se cambia el tipo de una variable, se conoce como “cast”. Esta técnica resulta muy útil para implementar patrones como el de variables opacas, pero es una espada de Damocles: se salta las comprobaciones de tipo del sistema, pudiendo producir errores (chungos) en tiempo de ejecución.

Portabilidad

Uno de los objetivos de C era la portabilidad del código. Se ideó precisamente en una época en la que cada máquina tenía un sistema operativo en ensamblador a medida, y su propósito era unificar la creación del sistema operativo, de manera que un compilador generara el código máquina necesario para cada familia de computadoras.

La idea era buena, pero C tenía sus deficiencias y cada empresa decidió subsanarlas como le vino en gana. Como la cosa se iba de madre, decidieron sacar el estándar POSIX, de manera que se unificaran las cosas que hace el sistema operativo para utilizarse de la misma manera desde C.

Sin embargo, las empresas hicieron lo que les vino en gana: IBM lo soporta perfectamente en algunas máquinas, parcialmente en otras y… bueno, nada en otras. Y Microsoft, que sacó su propio “des-estándar”.

¿Queréis ejemplos? La llamada al sistema “fork”, en solaris es “fork1”, ya que “fork” hace algo ligeramente diferente apesar de tener exactamente los mismos parámetros. Resultado: leaks, procesos zombies, …

El resultado es un código que no puede usarse sin más en los distintos sistemas operativos, sino que requiere mucho tiempo de adaptación.

Poco eficiente de programar

A menudo requiere mucho tiempo hacer cualquier cosa. Resulta indispensable el uso de librerías externas, tales como la libglib para poder realizar programas en tiempos aceptables.

La funcionalidad que otorga la API estándar es bastante reducida.

Malos sistemas de pruebas

Las propias características del lenguaje hacen que sea dificil realizar sistemas de pruebas unitarias eficientes. No es fácil crear mocks ni hacer tests que se encuentren automáticamente. Además, hay que compilar el código, y una vez compilado se suelen ocultar las características. Una vez compilado, no es posible acceder a las funciones de forma individual (si las opciones de compilación son correctas).

Existen buenos depuradores, pero la depuración es un proceso manual que requiere mucho tiempo. Es más agradable trabajar con sistemas de pruebas que ya realizan esa depuración por nosotros.

Pequeño es mejor

Bueno, esto no es una desventaja, sino una característica: escribir funciones pequeñas permite tener más controlada la gestión de memoria y resulta más sencillo entender el código. Esto es algo que los programadores C de verdad saben y usan.

A menudo, las funciones C tienden a crecer debido a la necesidad de varias líneas de código para realizar cualquier tipo de operación compleja: acceso a variables opacas, comprobación de errores, gestión de memoria,… Por lo que resulta complejo conseguir funciones de 2-3 líneas. Sin embargo, marcarse un límite de 20 líneas por función puede ser un buen ejercicio de autocontrol.

Conclusión

El lenguaje de programación C provocó un antes y un después. Hay gente que lo odia y gente que lo ama, aunque abundan más los primeros que los segundos.

En mi opinión, C es un lenguaje para conocer y respetar, de la misma manera que se respeta a un anciano: por muy rápido y listo que te creas, él cuenta con la experiencia.

Saber C siempre es útil, aunque no tenga objetos y parezca completamente distinto de tu lenguaje favorito.