2012-01-23 16 views
14

Duplicar posible:
What is the point of function pointers?¿cuál es el uso de indicadores de función?

Estoy tratando de entender donde en los escenarios prácticos se utilizan punteros de función. y también puede alguien darme un ejemplo práctico donde tenemos que pasar la función como un argumento para otra función.

+0

Esto es C#, pero también entra en C/C++ y la practicidad de los indicadores de función: http://stackoverflow.com/questions/667410/the-benefits-of-using-function-pointers – Algorhythm

Respuesta

18

Los punteros de función pueden ser útiles cuando desea crear callback mechanism, y necesitan pasar la dirección de una función a otra función.

También pueden ser útiles cuando quiere almacenar una serie de funciones, para llamar dinámicamente, por ejemplo.

8

Un uso común es implementar un callback function.

Intente ordenar algo utilizando la función de biblioteca qsort. Su último parámetro es un puntero a la función de comparación escrita por usted.

5

Lo primero que me viene a la mente como una aplicación muy útil es un botón. Tome el siguiente código:

int buttonID = CreateButton ("Click Me!", 100, 100, 200, 100, onClick); 

Esto crearía un botón al (100,100) con una anchura de 200 y una altura 100. Cada vez que hace clic en él, onclick se llama.

Uso algo similar en un contenedor personal de API de Windows. Hace que crear botones, etc. sea mucho más fácil.

3

Bueno, la respuesta de stock # 1 es: qsort. La rutina de comparación que usará qsort se pasa como un puntero de función. Muchas otras funciones de "algoritmo genérico" tomarán comparadores de manera similar; p.ej. tal vez una implementación hashtable podría aceptar su función hash.

Los juegos de herramientas de interfaz gráfica de usuario y los marcos de aplicación (por ejemplo, Gnome/Gtk +/Glib) a menudo aceptan punteros de funciones como "devoluciones de llamada" para temporizadores o eventos de interfaz de usuario. (Por ejemplo, "llamar a esta función cada vez que se hace clic en este botón" o "... cada vez que expira este temporizador")

De hecho, la mayoría de los códigos "OOP-like" o "event-driven" en C aceptarán indicadores de función para un razon similar

4

Hay dos usos principales para los punteros de función:

  • devoluciones de llamada - se utiliza para controladores de eventos, especialización analizador, pasando función de comparación ...
  • plugins y extensiones - los punteros a funciones proporcionadas por los plugins o las extensiones de biblioteca se reúnen mediante una función estándar GetProcAddress, dlsym o similar, que toma el identificador de función como nombre y devuelve un puntero de función. Absolutamente vital para API como OpenGL.
1

Puede usarlo para pasar una devolución de llamada a una función. Por ejemplo, es posible que desee ordenar una matriz usando qsort().Esta función tiene una función de comparación como uno de sus argumentos, lo que significa que puede utilizar sus propias órdenes de clasificación:

// All odd numbers are before even numbers 
int cmpoddeven(const void *xp, const void *yp) { 
    int x = *((int*) xp); 
    int y = *((int*) yp); 
    if(x == y) 
    return 0; 
    if(x % 2 == y % 2) { 
    return (x < y ? -1 : 1); 
    if(x % 2 == 1) 
    return -1; 
    return 1; 
} 

int main() { 
    int array[] = {1, 2, 3, 4, 5}; 
    // calling qsort with cmpoddeven as the comparison function 
    qsort(array, 5, sizeof(int), &cmpoddeven); 
    // array == {1, 3, 5, 2, 4}; 
} 
1

En casos más, que es esencialmente la forma de hacer C dependency inversion. El artículo wiki dice:

A. Los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deberían depender de abstracciones. B. Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.

El ejemplo clásico de qsort hace esto en el sentido de que la función de clasificación de nivel superior no depende del método de tipo, tamaño, o la comparación de los datos a ser ordenados. Por lo tanto, si tiene qsort() una matriz de entradas, los detalles son sizeof(int) y su implementación de comparación. La abstracción es una matriz de elementos de tamaño arbitrario y una función que compara elementos de ese tipo.

Véase también: Inversion of Control.

Estoy sorprendido de que nadie haya mencionado pthread_create() como ejemplo.

El único uso común que se me ocurre no se puede generalizar ya que la inversión de dependencia está implementando un control de flujo similar a un conmutador en tipos de datos no conmutables. Por ejemplo, si alguna vez ha querido activar una cadena, cree matrices asignando claves de cadena ordenadas para que funcionen punteros y realice una búsqueda binaria. No es O (1) como un interruptor, pero es mejor que hacer ciegamente strcmp() en un gran if-else hasta que encuentres una coincidencia. Pero tal vez no sea mejor que tokenizar la cadena y usar un interruptor real.

4

Las rutinas de devolución de llamada parecen ser el escenario más común presentado hasta ahora. Sin embargo, hay muchos otros ...

Máquinas de estados finitos donde los elementos de las matrices (multidimensionales) indican la rutina que procesa/maneja el siguiente estado. Esto mantiene la definición del FSM en un lugar (el conjunto).

Las funciones de habilitación y la desactivación de funciones se pueden realizar utilizando punteros a funciones. Puede tener funciones que desee habilitar o deshabilitar que hagan cosas similares pero distintas. En lugar de poblar y saturar su código con if-else, construye variables de prueba, puede codificarlo para que use un puntero de función, y luego puede habilitar/deshabilitar características cambiando/asignando el puntero a la función. Si agrega nuevas variantes, no tiene que rastrear todo su if-else o cambiar de mayúsculas y minúsculas (y corre el riesgo de perder una); en su lugar, simplemente actualice su puntero de función para habilitar la nueva característica, o deshabilite la anterior.

Reducción del desorden de código Me referí a esto en el ejemplo anterior. Ejemplos como ...

switch (a) { 
case 0: 
    func0(); 
    break; 
case 1: 
    func1(); 
    break; 
case 2: 
    func2(); 
    break; 
case 3: 
    func3(); 
    break; 
default: 
    funcX(); 
    break; 
} 

puede simplificarse a ...

/* This declaration may be off a little, but I am after the essence of the idea */ 
void (*funcArray)(void)[] = {func0, func1, func2, func3, funcX}; 
... appropriate bounds checking on 'a' ... 
funcArray[a](); 

hay muchos más. Espero que esto ayude.

+1

FWIW, la declaración debería ser 'void (* funcArray []) (void) = {func0, func1, func2 ...}; '(' funcArray' es una matriz de punteros a funciones ...). Recuerde que la declaración imita el uso; si la expresión en el código es 'funcArray [a]()', la declaración se estructurará de la misma manera. –

+1

@JohnBode - Muy apreciado. Aunque he trabajado con C durante más de 20 años, todavía me confundo con la sintaxis del puntero a la función. Por lo general, opto por la ruta de tipo más fácil (para mí) definiendo primero el puntero a la función y luego declarando una matriz de la variable typedef'ed. – Sparky

+0

@Sparky De acuerdo con respecto al typedef. Hace que las situaciones como matrices de indicadores de función o punteros a indicadores de función sean mucho más fáciles de leer. –

Cuestiones relacionadas