[gelöst] Function Pointer Definition die sich selbst als Parameter braucht


  • Mod

    Tobias Gerg schrieb:

    Bekommt man das irgendwie hin?

    Nein. Das ist eine direkte Folge der (rekursiven) Syntax für Typdeklarationen. Es ist in C (und entsprechend C++) unmöglich, eine Funktion zu deklarieren, die einen Zeiger auf sich selbst zurückgibt oder als Parameter enthält.
    In solchen Fällen muss ein beliebiger anderer Funktionstyp für den Parameter/Rückgabewert verwendet (oder zur Not void* wenn die Plattform entsprechende Konvertierungen zulässt) und dann entsprechend gecastet werden.

    Alternativ kann man den Zeiger in ein struct verpacken. Durch geeignet Vorwärtsdeklaration erübrigt sich dann der Cast (und wird durch einen entsprechenden Memberzugriff ersetzt).

    typedef struct foo foo;
    
    foo f(void);
    
    struct foo { foo (*p)(); };
    
    foo f(void) { return (foo){&f}; }
    


  • Ein Funktionsname zerfällt außer bei & und sizeof immer in einen Zeiger auf den Funktionstyp. Wenn du den mit * wieder dereferezierst, hast du wieder den Funktionsnamen, welcher wieder in einen Zeiger zerfällt usw.
    Deswegen sind die Funktionsaufrufe

    f();
    (*f)();
    (**f)();
    (***f)();
    

    usw. auch äquivalent.
    Das solltest du aber alles eigentlich selbst wissen, da du ja ein relativ komplexes Framework verwendest.



  • Wutz schrieb:

    Ein Funktionsname zerfällt außer bei & und sizeof immer in einen Zeiger auf den Funktionstyp. Wenn du den mit * wieder dereferezierst, hast du wieder den Funktionsnamen, welcher wieder in einen Zeiger zerfällt usw.
    Deswegen sind die Funktionsaufrufe

    f();
    (*f)();
    (**f)();
    (***f)();
    

    usw. auch äquivalent.
    Das solltest du aber alles eigentlich selbst wissen, da du ja ein relativ komplexes Framework verwendest.

    Das ist mir klar, aber ich will als zweiten Parameter einen output parameter haben (also & fall Edit: Adresse des Funktionszeiger ).

    In etwa so

    typedef int (*pExecFunc)();
    
    int MyExecFunc1(void *pExecStruct, pExecFunc* ppExec)
    {
        return 0;		
    }
    
    int MyExecFunc2(void *pExecStruct, pExecFunc* ppExec)
    {
    /* Complex calculation */
    	*ppExec = &MyExecFunc1;
    	return 0;
    }
    
    int main( int argc, char *argv[] )
    {
    	pExecFunc t = &MyExecFunc2;
    	MyExecFunc2(0, &t);
    	(*t)(0, t);  // Soll MyExecFunc1 aufrufen.
    
    	return 0;
    }
    

    @Camper
    Auch dir danke für die Anregung...



  • Wutz schrieb:

    Ein Funktionsname zerfällt außer bei & und sizeof immer in einen Zeiger auf den Funktionstyp.

    Aber die Adresse eines Funktionszeigers ist kein Zeiger auf eine Funktion.



  • Das hat schon Sinn denke ich:

    typedef int (*fun) ();
    
    int main()
    {
      fun array[10];
    
      fun *pFun = array;
    
      return 0;
    }
    

    😕



  • Du hast noch zuviele &,* drin:

    typedef int (*pExecFunc)();
    
    int MyExecFunc1(void *pExecStruct, pExecFunc* ppExec)
    {
    
        return 0;
    }
    
    int MyExecFunc2(void *pExecStruct, pExecFunc* ppExec)
    {
    /* Complex calculation */
        *ppExec = MyExecFunc1;
        return 0;
    }
    
    int main( int argc, char *argv[] )
    {
        pExecFunc t = MyExecFunc2;
        MyExecFunc2(0, &t);
        t(0, t);
    
        return 0;
    }
    


  • Wutz schrieb:

    Du hast noch zuviele &,* drin:

    typedef int (*pExecFunc)();
    
    int MyExecFunc1(void *pExecStruct, pExecFunc* ppExec)
    {
    
        return 0;
    }
    
    int MyExecFunc2(void *pExecStruct, pExecFunc* ppExec)
    {
    /* Complex calculation */
        *ppExec = MyExecFunc1;
        return 0;
    }
    
    int main( int argc, char *argv[] )
    {
        pExecFunc t = MyExecFunc2;
        MyExecFunc2(0, &t);
        t(0, t);
    
        return 0;
    }
    

    Ok..., aber abgesehen von den zu vielen & und * im Beispielcode brauche ich den Pointer auf den Function Pointer um t als output Variable verwenden zu können.


  • Mod

    Da der Funktionsparameter sowieso ein Objektzeiger wäre, könnte an der Stelle auch einfach void* verwendet werden.

    typedef int (*pExecFunc)(void* pExecStruct, void* ppExec);
    
    int MyExecFunc1(void *pExecStruct, void* ppExec)
    {
    
        return 0;
    }
    
    int MyExecFunc2(void *pExecStruct, void* ppExec)
    {
    /* Complex calculation */
        pExecFunc* ppExec_ = ppExec;
        *ppExec_ = MyExecFunc1;
        return 0;
    }
    
    int main( int argc, char *argv[] )
    {
        pExecFunc t = MyExecFunc2;
        t(0, &t); // MyExecFunc2
        t(0, &t); // MyExecFunc1
    
        return 0;
    }
    


  • Dann ist das mit Compilerwarnungen aber mau. Komplett typsicher wird das nicht gehen, weil die Signatur unendlich lang würde, aber zwei Schritte hineinzugehen scheint mir noch sinnvoll:

    int MyExecFunc(void *context, int (*exec)(void*, int (*)())) {
      ...
    }
    

    ...auf die Art lässt sich exec in MyExecFunc ganz natürlich verwenden, und vor allem kann der Compiler vernünftig warnen, wenn etwas anderes als ein Funktionszeiger dort hineingeworfen wird.

    Wenn es viele solcher Funktionen geben soll, rate ich aber dringendst zur Verwendung passender typedefs. Für jemanden, der Funktionszeiger nicht gewohnt ist, sieht so eine Signatur schon reichlich wild aus.



  • @Camper
    An void* haben wir auch schon gedacht, allerdings kann es sein, das wir die Funktion die übergeben wird auch in einer Exec Funktion aufrufen wollen, dann sind wir mit dem Funktionszeiger besser dran, da man in intuitiver verwenden kann ohne vorher casten zu müssen.

    @all
    Danke an alle die sich an der Diskussion beteiligt haben. War wie immer eine super Hilfe 👍 👍 👍

    :xmas2:
    Tobi


Anmelden zum Antworten