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



  • Hallo zusammen,

    wir diskutieren hier gerade folgenden Fall.

    typedef int (*ExecFunc)(void* pExecStruct, ExecFunc** ppExecFunc);
    

    Bekommt man das irgendwie hin? Uns ist nämlich kein direkter Weg eingefallen.

    Ich bin für jede Hilfe dankbar.

    Gruß
    Tobi



  • was solln das werden wenns fertig ist?



  • Geht in ein recht komplexes Framework, das tut aber nichts zur Sache. Ich möchte nur wissen ob es irgendwie möglich ist, so etwas zu machen.



  • Mir fällt da auch nix ein. Ausser, falls ihr das ändern könnt, die Exec-Funktionenliste in ner Struktur übergeben.
    Dann habt ihr forward-deklaration zur Verfügung



  • ScottZhang schrieb:

    Mir fällt da auch nix ein. Ausser, falls ihr das ändern könnt, die Exec-Funktionenliste in ner Struktur übergeben.
    Dann habt ihr forward-deklaration zur Verfügung

    Danke für die Antwort. Sowas in die Richtung habe ich mir schon fast gedacht... 😞 . Wenn noch jemanden was anderes einfällt, dann immer her damit...

    :xmas2: :xmas1: :xmas2:



  • typedef int (*ExecFunc)(void* pExecStruct, int(*pExecFunc)());
    

    Doppelzeiger auf Funktionen sind immer sinnfrei.



  • Wutz schrieb:

    typedef int (*ExecFunc)(void* pExecStruct, int(*pExecFunc)());
    

    Doppelzeiger auf Funktionen sind immer sinnfrei.

    Danke für die Antwort. 👍

    Das mit dem "sinnfrei" verstehe ich nicht. Wir haben in einer ExecFunction eine Berechnung anhand der die nächste ExecFunction ausgewählt wird. Der Pointer ist ein output Pointer, von daher 😕


  • 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