Archivo por meses: agosto 2006

Punteros a función en C

Bueno, unas de las cosas que me quedan en el tintero es poner ejemplos de código. Con esta entrada espero poner fin a esto hablando de los punteros a función en C.

Muchos de los que hayan programado en C sabrán lo infernal que puede resultar el uso de punteros. Hoy, para rizar el rizo, voy a hablaros de los punteros a función.

Como sucede con los punteros normales (a variables), un puntero a función no es más que un apuntador que nos dice donde se encuentra una función. La pregunta ahora es… ¿Y para qué nos puede servir esto? Pues la verdad es que para muchas cosas, por ejemplo, cuando se dispone de un algoritmo de ordenación en C y queremos que este nos sirva para cualquier cosa, lo interesante es tener un mecanismo que nos permita comparar dos elementos. Podemos hacer el algortimo de modo que sólo soporte un tipo de datos o podemos hacer que soporte cualquier tipo. Esto lo hacemos con punteros a funciones. Vamos a ver un ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* Ordena los elementos de una lista de menor a mayor.
* La lista es genérica y almacena sus elementos como punteros a cualquier cosa (void *).
* Se utiliza una función de comparación a la que se le pasan dos elementos de la lista y nos
* informa si el primero es mayor que el segundo.
*/
void ordenar( lista_t lista, int (*cmp)(void *elm1, void *elm2) ) {
   void *elem1, *elem2, *tmp;
   int numero_elementos = lista_numero_elementos( lista );
   int i, c;
 
   for( i = 0; i < numero_elementos; i ++ )
   {
      for( c = 0; c < numero_elementos-i-1; c ++ )
      {
         elem1 = lista_obtener_elemento( lista, c );
         elem2 = lista_obtener_elemento( lista, c+1 );
         /* Si elem1 > elem2 Entonces los intercambiamos.
         * Para hacer esta comparación, utilizamos la función del usuario. */
         if( cmp( elem1, elem2 ) )
         {
            lista_asignar_elemento( lista, c, elem2 );
            lista_asignar_elemento( lista, c+1, elem1 );
         } /* if( cmp( elem1, elem2 ) ) */
      } /* for( c = 0; c < numero_elementos-i-1; c ++ ) */
   } /* for( i = 0; i < numero_elementos; i ++ ) */
}
 
/**
* Compara elm1 y elm2, teniendo en cuenta que estos deben ser enteros.
* Si elm1 es mayor que elm2, devuelve un valor distinto que 0. En cualquier
* otro caso, devolverá 0.
*/
int CompararEnteros( void *elm1, void *elm2 )
{
   int a, b;
   a = (int)elm1;
   b = (int)elm2;
   return a > b;
}
 
/* Código del usuario */
 
/* Para ordenar la lista de enteros: */
ordenar( lista, CompararEnteros );
 
 
/* Código del usuario */

Bueno, espero que no sea necesario que explique qué hacen las funciones de la lista. Como vemos, con este mecanismo podemos usar enteros, flotantes, estructuras o imágenes. En verdad ahora podríamos ordenar una lista de cualquier cosa. Esto se consigue precisamente por el uso de punteros a función. Los que hayan hecho porgramación orientada a objetos se darán cuenta que esto se podría haber hecho con herencia.

En la línea 7, tenemos int (*cmp)(void *elm1, void *elm2). Esto es precisamente la declaración de una variable cmp que será un puntero a una función que devolverá un entero y que acepta dos parámetros de tipo void *. Para utilizar el puntero, sólo hay que hacer como si fuera una función normal y corriente:

cmp( param1, param2 );

En general, la definición de todo puntero a función es de la forma:

tipo_de_retorno (*nombre_de_la_variable)( parametros );

Para asignar a un puntero a función la dirección de un puntero, no hay más que hacer una signación normal:

puntero_a_función = función;

La función sería sin los argumentos.

Esto es sólo un ejemplo de lo que se puede hacer. Los punteros a funciones también pueden emplearse para crear menús dinámicos en los que queremos que, cuando se les pulse, se llame a una función (esta se pasaría como puntero a función). En muchas prácticas de las asignaturas de sistemas operativos, al utilizar señales tipo UNIX, se utilizan punteros a funciones. Se utilizan cuando decimos: «pues cuando llegue la señal SIGXXXX, quiero que llames a esta función». Cuando se hace programación multihilo (o con threads), también se usan los punteros a función.

Bueno, esto ha sido una pequeña introducción. Si a alguien le interesa saber más, puede decirlo en los comentarios. Si se me ocurre poner algo más, ya lo haré. Espero que os haya servido de ayuda.

Estancia en Ciudad Real

Aunque no lo dijera antes, este fin de semana he estado en Ciudad Real. Debería haberme quedado hasta hoy, pero bueno.

La verdad es que me lo he pasado genial. El sábado fue la primera vez que asistí a la zurra. Sin duda alguna, ha sido una de mis experiencias más refrescantes con el vino. Supongo que tendrá que ver con el hecho de que nos lo tirabamos todo por encima. Os pondría fotos de este evento, pero como que llevar una cámara o un teléfono móvil con cámara era todo un peligro (ya sabemos que los líquidos y los circuitos se llevan mal). Aún así, podéis ver en la galería de imágenes algunas fotos del resultado final (son en las que voy con una camiseta blanca con bordes azules).

Por la noche aproveché para jugar a rol. La partida duró desde las 3:00 de la madrugada hasta las 7:00 (vimos amanecer, ¡qué ilusión!). De esa noche, lo más sorprendente pudo ser una gigantesca bandada de gorriones (es una pena que no tuviese una videocámara decente para grabarlo).

El domingo fue más tranquilo. Partida de rol y concerto de Carlos Nuñez por la noche. La verdad es que teniendo en cuenta que pasé la mayor parte del día durmiendo, no dió tiempo para mucho :-P.

El lunes era el día gordo de la pandorga. Tendría que haberme quedado, pero las obligaciones (vamos, la práctica que tengo para septiembre), pesan mucho :'(. Así que toco volverse. Pero el próximo año prometo que me quedaré a la pandorga completa.

Lo que aún está por decidir es si iré a las fiestas de Ciudad Real y a las del pueblo. Ya veremos.