<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d9665506\x26blogName\x3dMi+blog!\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLUE\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttp://zirrus.blogspot.com/search\x26blogLocale\x3des_ES\x26v\x3d2\x26homepageUrl\x3dhttp://zirrus.blogspot.com/\x26vt\x3d-7334819199369966265', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>

martes, diciembre 28, 2004

Genericidad en C

Uno de los grandes problemas con el que enfrentarse cuando usamos C es crear código genérico, un código que pueda ser reutilizado en futuras implementaciones sin tener que estar re-implementando continuamente código que ya habíamos pensado y usado.

En un anterior post ya he hablado de la estructuración de la orientación a objetos y sobre cómo deberíamos enfrentarnos a las diferencias de programación entre el paradigma imperativo y el paradigma orientado a objeto. Así mismo, también he comentado mi afición a C.

Bien, el problema ahora es: ¿Cómo generar código "genérico"?. Como ejemplo tomo uno de mis proyectos de programación. Consiste en una implementación de una estructura de datos dinámica, en este caso una pila. Así pues: ¿Cómo podemos conseguir una implementación de una estructura de datos dinámica ,como lo es una pila, que sea genérica y programada en C? Debemos conseguir una implementación de una pila que nos sea útil para "cualquier" código que necesite una pila (o varias).

Bueno, antes que nada recordar que C no tiene las cualidades de la orientación a objetos (como podría tener C++) y que por lo tanto no tiene las facilidades de la genericidad (así como otra muchas: reutilización, modularidad y todas esas maravillas que se nos vende con los lenguajes orientados a objetos).

Problemas fundamentales:
  1. ¿Cómo guardar los datos?. La única forma "genérica" que podemos usar en C es el tipo de datos void. En nuestro caso, el uso de un puntero a void nos permitirá guardar cualquier tipo de datos en nuestra pila.
  2. ¿Cuanta memoria utilizamos?. Uno de los problemas a lo que debemos enfrentarnos. Si queremos guardar los datos en un puntero a void, deberemos saber cuánto ocupan lo datos. En la pila, deberemos saber cuánto ocupa los datos de cada nodo de la pila para en un futuro poder "jugar" con ellos (duplicarlos, copiarlos, etc).
  3. ¿Cómo enlazarla?. La única forma que tenemos es crear una librería en C para en un futuro ser importada (con el include) por aquel código cliente que quiera usar nuestro código "genérico". No podemos hacer uso de packages, importaciónes raras ni nada por el estilo.
  4. ¿Qué pasa si utilizamos funciones que necesitan saber el tipo de datos que estamos usando?. En este caso, nuestra única opción dería guardar el tipo de datos almacenados con alguna variable y discriminar las implementaciones para cada tipo. Este es el principal problema que encontramos cuando el lenguaje no tiene genericidad, pues el programador acaba programando cosas diferentes para cada tipo de datos.
  5. Y sobre todo, ya que estamos realizando código genérico, debemos implementar correctamente nuestra librería para que funcione al 100%, es decir, el control de errores debe ser meticuloso, así como el control y administración de la memoria dinámica si se usara. El número de funciones de nuestra librería debería ser adecuado para su uso, por ejemplo, en la implementación de una pila genérica, no solo debemos implementar funciones para apilar y desapilar, sino también funciones de gran utilidad como destruir pilas, copiarlas, concatenarlas, etc, pues para eso estamos construyendo código genérico y reutilizable.
En general, podemos aproximarnos bastante a una implementación genérica, pero nunca la alcanzaremos en su totalidad. Por ejemplo, el uso de punteros a void podría implicar tener diferentes tipos de datos (char, int, etc) en una misma pila. Esto obligaría al control del contenido de la pila así como otros procedimientos.

El número de problemas que aparecen suele ser bastante grande, pero con un poco de paciencia y de conocimientos de C se pueden conseguir maravillas. Como todo, el hecho de sentarse y ponerse a pensar cómo conseguir un poco de genericidad en C, permite conocer las limitaciones y virtudes del lenguaje de programación que estamos usando.

En cuanto pueda subiré mi implementación de la pila genérica que he estado usando como ejemplo.

Nos vemos!!