c - funktionspointer - funktionpointer




Verstehen typedefs für Funktionszeiger in C (5)

Ich war immer ein bisschen ratlos, wenn ich den Code anderer Leute las, der Typen für Zeiger auf Funktionen mit Argumenten hatte. Ich erinnere mich, dass ich eine Weile gebraucht habe, um zu einer solchen Definition zu gelangen, als ich versuchte, einen numerischen Algorithmus zu verstehen, der vor einiger Zeit in C geschrieben wurde. Könnten Sie also Ihre Tipps und Gedanken zum Schreiben guter Typdefinitionen für Zeiger auf Funktionen (Do's und Do not's) teilen, warum sie nützlich sind und wie man die Arbeit anderer versteht? Vielen Dank!


Dies ist das einfachste Beispiel für Funktionszeiger und Funktionszeigerarrays, die ich als Übung geschrieben habe.

    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));
    }

Ein Funktionszeiger ist wie jeder andere Zeiger, aber er zeigt auf die Adresse einer Funktion anstelle der Adresse von Daten (auf Heap oder Stack). Wie jeder Zeiger muss er korrekt eingegeben werden. Funktionen werden durch ihren Rückgabewert und die Arten von Parametern definiert, die sie akzeptieren. Um eine Funktion vollständig beschreiben zu können, müssen Sie ihren Rückgabewert angeben, und der Typ jedes Parameters ist akzeptiert. Wenn Sie eine solche Definition eingeben, geben Sie ihr einen 'Anzeigenamen', der das Erstellen und Referenzieren von Zeigern mit dieser Definition erleichtert.

Nehmen wir zum Beispiel an, Sie haben eine Funktion:

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

dann der folgende typedef:

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

kann verwendet werden, um auf diese doMulitplication Funktion zu verweisen. Es definiert einfach einen Zeiger auf eine Funktion, die einen Gleitkommawert zurückgibt und zwei Parameter vom Typ float nimmt. Diese Definition hat den pt2Func . Beachten Sie, dass pt2Func auf eine beliebige Funktion pt2Func kann, die einen pt2Func zurückgibt und 2 pt2Func .

So können Sie einen Zeiger erstellen, der wie folgt auf die doMultiplication-Funktion verweist:

pt2Func *myFnPtr = &doMultiplication;

und Sie können die Funktion mit diesem Zeiger wie folgt aufrufen:

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

Das liest sich gut: http://www.newty.de/fpt/index.html


Verwenden Sie typedefs, um kompliziertere Typen zu definieren, zB Funktionszeiger

Ich werde das Beispiel nehmen, eine Zustandsmaschine in C zu definieren

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

Jetzt haben wir einen Typ namens action_handler definiert, der zwei Zeiger akzeptiert und einen int zurückgibt

Definieren Sie Ihre Zustandsmaschine

    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;

Der Funktionszeiger auf die Aktion sieht wie ein einfacher Typ aus, und typedef dient hauptsächlich diesem Zweck.

Alle meine Event-Handler sollten nun dem von action_handler definierten Typ entsprechen

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

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

Verweise:

Experte C Programmierung von Linden


cdecl ist ein großartiges Werkzeug, um seltsame Syntax wie Funktionszeigerdeklarationen zu entschlüsseln. Sie können es verwenden, um sie auch zu generieren.

Soweit es typedef ist, komplizierte Deklarationen zu vereinfachen, um sie für zukünftige Wartungszwecke analysieren zu können (ich selbst oder andere), empfehle ich, typedef aus kleinen typedef und diese kleinen Teile als Bausteine ​​für größere und kompliziertere Ausdrücke zu verwenden. Beispielsweise:

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

eher, als:

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

cdecl kann dir mit diesem Zeug helfen:

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 )

Und ist (genau) genau, wie ich dieses verrückte Chaos oben erzeugt habe.


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;
}

Ausgabe davon ist:

22

6

Beachten Sie, dass derselbe math_func Definer für die Deklaration der beiden Funktionen verwendet wurde.

Der selbe Ansatz von typedef kann für extern struct verwendet werden (mit sturuct in einer anderen Datei).





typedef