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.
