sirven - todas las funciones de c++




Entendiendo typedefs para punteros de función en C (5)

Siempre he estado un poco perplejo cuando leí el código de otras personas que tenía ajustes de tipo para los punteros a las funciones con argumentos. Recuerdo que me tomó un tiempo llegar a esa definición mientras intentaba entender un algoritmo numérico escrito en C hace un tiempo. Entonces, ¿podría compartir sus sugerencias e ideas sobre cómo escribir buenas definiciones de tipo para los punteros a las funciones (Qué hacer y qué no hacer)? ¿Por qué son útiles y cómo entender el trabajo de otros? ¡Gracias!


Este es el ejemplo más simple de punteros de función y matrices de punteros de función que escribí como un ejercicio.

    typedef double (*pf)(double x);  /*this defines a type pf */

    double f1(double x) { return(x+x);}
    double f2(double x) { return(x*x);}

    pf pa[] = {f1, f2};


    main()
    {
        pf p;

        p = pa[0];
        printf("%f\n", p(3.0));
        p = pa[1];
        printf("%f\n", p(3.0));
    }

Un puntero de función es como cualquier otro puntero, pero apunta a la dirección de una función en lugar de a la dirección de los datos (en el montón o pila). Como cualquier puntero, necesita ser escrito correctamente. Las funciones se definen por su valor de retorno y los tipos de parámetros que aceptan. Entonces, para describir completamente una función, debe incluir su valor de retorno y se acepta el tipo de cada parámetro. Cuando tecleas una definición de este tipo, le asignas un "nombre descriptivo" que facilita la creación y referencia de punteros usando esa definición.

Así, por ejemplo, supongamos que tiene una función:

float doMultiplication (float num1, float num2 ) {
    return num1 * num2; }

entonces el siguiente typedef:

typedef float(*pt2Func)(float, float);

se puede utilizar para apuntar a esta función doMulitplication . Es simplemente definir un puntero a una función que devuelve un flotador y toma dos parámetros, cada uno de tipo flotante. Esta definición tiene el nombre pt2Func . Tenga en cuenta que pt2Func puede apuntar a CUALQUIER función que devuelve un flotador y toma 2 flotadores.

Por lo tanto, puede crear un puntero que apunte a la función doMultiplication de la siguiente manera:

pt2Func *myFnPtr = &doMultiplication;

y puede invocar la función utilizando este puntero de la siguiente manera:

float result = (*myFnPtr)(2.0, 5.1);

Esto hace una buena lectura: http://www.newty.de/fpt/index.html


Utilice typedefs para definir tipos más complicados, es decir, punteros de función

Tomaré el ejemplo de definir una máquina de estados en C

    typedef  int (*action_handler_t)(void *ctx, void *data);

Ahora hemos definido un tipo llamado action_handler que toma dos punteros y devuelve un int.

define tu máquina de estado

    typedef struct
    {
      state_t curr_state;   /* Enum for the Current state */
      event_t event;  /* Enum for the event */
      state_t next_state;   /* Enum for the next state */
      action_handler_t event_handler; /* Function-pointer to the action */

     }state_element;

La función de puntero a la acción parece un tipo simple y typedef sirve principalmente para este propósito.

Todos mis controladores de eventos ahora deben adherirse al tipo definido por action_handler

    int handle_event_a(void *fsm_ctx, void *in_msg );

    int handle_event_b(void *fsm_ctx, void *in_msg );

Referencias:

Programación Expert C de Linden


cdecl es una gran herramienta para descifrar sintaxis extraña como declaraciones de puntero de función. Puedes usarlo para generarlos también.

En cuanto a los consejos para hacer que las declaraciones complicadas sean más fáciles de analizar para el mantenimiento futuro (por usted o por otros), recomiendo hacer typedef de trozos pequeños y usar esas piezas pequeñas como bloques de construcción para expresiones más grandes y más complicadas. Por ejemplo:

typedef int (*FUNC_TYPE_1)(void);
typedef double (*FUNC_TYPE_2)(void);
typedef FUNC_TYPE_1 (*FUNC_TYPE_3)(FUNC_TYPE_2);

más bien que:

typedef int (*(*FUNC_TYPE_3)(double (*)(void)))(void);

cdecl puede ayudarte con estas cosas:

cdecl> explain int (*FUNC_TYPE_1)(void)
declare FUNC_TYPE_1 as pointer to function (void) returning int
cdecl> explain double (*FUNC_TYPE_2)(void)
declare FUNC_TYPE_2 as pointer to function (void) returning double
cdecl> declare FUNC_TYPE_3 as pointer to function (pointer to function (void) returning double) returning pointer to function (void) returning int
int (*(*FUNC_TYPE_3)(double (*)(void )))(void )

Y es (de hecho) exactamente como generé ese desorden loco arriba.


int add(int a, int b)
{
  return (a+b);
}
int minus(int a, int b)
{
  return (a-b);
}

typedef int (*math_func)(int, int); //declaration of function pointer

int main()
{
  math_func addition = add;  //typedef assigns a new variable i.e. "addition" to original function "add"
  math_func substract = minus; //typedef assigns a new variable i.e. "substract" to original function "minus"

  int c = addition(11, 11);   //calling function via new variable
  printf("%d\n",c);
  c = substract(11, 5);   //calling function via new variable
  printf("%d",c);
  return 0;
}

La salida de esto es:

22

6

Tenga en cuenta que se ha utilizado el mismo definidor math_func para declarar la función.

Se puede utilizar el mismo enfoque de typedef para estructuras externas (usando sturuct en otro archivo).





typedef