Archivos mensuales: febrero 2015

Control de errores

Uno de los grandes problemas al programar es realizar el control de los errores. Por diversos motivos me ha tocado hacer un trabajo de estudio sobre qué opciones tenemos para realizar el control de los errores de una aplicación.

La verdad es que hubiese estado muy bien hacer una tormenta de ideas al respecto, pero en estos momentos estamos todos demasiado atareados.

El siguiente texto, sin pretender ser una guía exhaustiva de lo que es el control de errores, sí busca poner un punto de partida para todo aquel que quiera ver qué mecanismos hay para este fin.

Sigue leyendo Control de errores

Tratamiento de cadenas en C

Cuando empezamos a programar en C una de las cosas que probablemente más nos cuesta controlar es el tratamiento de cadenas.

El lenguaje C es de bastante bajo nivel, por lo que sus tipos de datos básicos son muy cercanos a lo que la máquina puede utilizar. Los ordenadores no entienden de cadenas, pero sí de direcciones de memoria. De hecho, no existe un tipo de cadena, sino que se usan arrays de bytes. Y lo mejor de todo, ¡en C es el programador el que debe conocer la longitud del array! (cuanto bien, y a la vez cuánto mal, han hecho los lenguajes modernos).

Todas las funciones del estándar de C presuponen que una cadena es un array de bytes donde el último carácter es un nulo.

No voy a entrar en más detalles sobre que son las cadenas. Si quieres aprender cómo se programa con ellas puedes leer Cadenas de caracteres del manual Programación en C de  wikibooks.

Quien más y quien menos habrá visto que muchos problemas de seguridad en bibliotecas en C viene precisamente del tratamiento de cadenas. Casi se podría decir que si tienes que hacer un programa que tenga que manejar cadenas es aconsejable que mires cualquier otra cosa que no sea C. Aún así, esto no siempre será posible.

En el lugar en el que trabajo hemos empezado a cambiar el modo en que utilizamos las cadenas. Para facilitar su uso y reducir la cantidad de errores que pueden producirse, hemos creado un nuevo tipo de cadena. Bueno, se parece más a un StringBuilder de java. Las motivaciones son varias:

  • Queremos un tratamiento de cadenas más rápido (tener que recorrer una cadena cada vez que quieres conocer su longitud no es óptimo).
  • Queremos poder trabajar con cadenas sin preocuparnos por reasignar constantemente memoria. ¿Habéis probado un strcat cuando estás usando arrays y el buffer de destino es más pequeño que la cadena a concatenar?
  • Para ciertas operatorias queremos poder tener cadenas con caracteres nulos. Las cadenas de C no se llevan bien con esto, pero nosotros creamos cadenas para mandar a dispositivos que no sólo aceptan el nulo, sino que ciertas operaciones lo requieren. Con las funciones estándar sería muy complicado esto.

Personalmente no creo que seamos los primeros en hacer algo así; no tengo la más mínima duda de que hay muchas personas con los mismos problemas.

Las ventajas de usar esta biblioteca son inmediatas:

  • Simplificamos el código por no tener que preocuparnos en si hay o no espacio para almacenar la cadena y en la gestión de este espacio.
  • Minimizamos errores pues no nos pasaremos nunca del buffer (siempre podemos quedarnos sin memoria).
  • Agilizamos el desarrollo al poder escribir directamente código que haga lo que queremos (es una consecuencia del primer punto).
  • Se pueden optimizar ciertas operaciones. Esto se debe a que no hay que estar constantemente recorriendo cadenas para medirlas o que al “liberar” una cadena, no hacemos free y malloc, sino que marcamos la cadena como de longitud 0 (que es más rápido y permite aprovechar la memoria).

¡Mucho ojo con esto! Que en el día a día de mi trabajo esta haya sido una buena solución no significa que lo sea para todos los casos. Siempre hay que evaluar convenientemente cada situación antes de decantarse por una u otra solución.

Pseudo lambdas con C

Últimamente se lleva mucho el tema de las funciones lambda y los closures en los lenguajes modernos. Un ejemplo es que en C++, desde la versión de 2011, ya las incorpora. Igualmente, otros lenguajes, como Ruby, Groovy o Rust ya han sido diseñados con esta característica.

Advertencia: el código que vamos a mostrar a continuación hace uso de extensiones de GNU C. Para ser exactos, hace uso de Statement Expressions y de Nested Functions. Estas extensiones solo son soportadas por unos pocos compiladores a parte de GNU C (ver Compiler support of GNU Statement Expressions en stackoverflow).

Aunque en C no existe nada parecido es factible simularlo. Todo sea dicho, el código puede ser muy feo. En el siguiente ejemplo tenemos una función que recorre un conjunto de elementos. Esta función la llamamos proccess. Por cada elemento procesado llama a una función de callback. Lo normal es crear la función de callback a parte, lo que hace que en ciertos casos sea incómodo el mantenimiento del código.

Otra opción es declarar la función de callback in situ justo en el momento que la necesitamos:

Como puede verse, nos aprovechamos de ‘({‘ y ‘})’ para declarar un bloque de código que devuelve el valor de la última expresión para crear nuestra función de callback. Como en este caso el nombre no nos importa, la llamamos ‘_’. Lo mejor de todo es que podemos repetir este nombre sin que por ello suponga que vaya a haber conflicto en la compilación ni en la ejecución.

Actualización 1: incluimos advertencia sobre compiladores.