Funktion void signal()
-
Von innen nach außen unter Berücksichtigung der Operatorenrangfolge und -assoziativität:
signal : signal wird deklariert
signal**(int sig, void (func)(int))* : ... als eine Funktion mit 2 Parametern, sig und func
*****signal(int sig, void (*func)(int)) : ... die einen Zeiger zurückliefert
(*signal(int sig, void (*func)(int)))(int) : ... der auf eine Funktion mit einem int-Parameter zeigt
void (*signal(int sig, void (*func)(int)))(int) : ... die void zurückliefert
-
signal ist eine Funktion, die als Rückgabewert einen Zeiger auf eine Funktion zurück gibt, die void zurück gibt und einen int als Parameter hat. signal selber hat zwei Parameter: Einen int und einen Zeiger auf eine Funktion, die void zurück gibt und einen int als Parameter hat.
Mit einem geschickten Typedef:
typedef void(*funcptr_t)(int); funcptr_t signal(int sig, funcptr_t func);
So ist es lesbar, oder? Aber wie konnte ich das an dem Originalausdruck ablesen (ich muss zugeben, für den habe ich ein paar Minuten gebraucht)? So:
void (*signal(int sig, void (*func)(int)))(int); signal ; // Deklaration von "signal". signal( ) ; // signal ist eine Funktion, *signal( ) ; // die einen Zeiger zurück gibt. (*signal( ))( ); // Genauer: Einen Zeiger auf eine Funktion. void (*signal( ))( ); // Eine Funktion, die void zurück gibt void (*signal( ))(int); // und int als Parameter hat. void (*signal( , ))(int); // signal hat 2 Parameter: void (*signal(int sig, ))(int); // Der Erste ist ein int, der den Namen "sig" erhält void (*signal(int sig, func ))(int); // Der zweite Parameter hat den Namen "func" void (*signal(int sig, *func ))(int); // func ist ein Zeiger void (*signal(int sig, (*func)( )))(int); // auf eine Funktion, void (*signal(int sig, void (*func)( )))(int); // die void zurück gibt void (*signal(int sig, void (*func)(int)))(int); // und einen int als Parameter hat
edit: Da war ich der Langsamste. Die Formatierung des Codes hat zu lange gedauert
.
Bashar schrieb:
Von innen nach außen unter Berücksichtigung der Operatorenrangfolge und -assoziativität:
Das wollte ich zunächst auch so schreiben, aber ich finde das äußerst missverständlich. "Innen" ist hier letztlich func. Und das ist ein schlechter Anfangspunkt, um den Ausdruck zu entziffern.
Und noch ein Nachtrag: Die Seite http://cdecl.ridiculousfish.com/ kann zwar nur Variablen und keine Funktionssignaturen entziffern, aber ist hier wohl trotzdem relevant.
-
SeppJ schrieb:
Bashar schrieb:
Von innen nach außen unter Berücksichtigung der Operatorenrangfolge und -assoziativität:
Das wollte ich zunächst auch so schreiben, aber ich finde das äußerst missverständlich. "Innen" ist hier letztlich func. Und das ist ein schlechter Anfangspunkt, um den Ausdruck zu entziffern.
Du hast es doch auch von innen nach außen gemacht, volkard auch. Geht auch nicht anders. Vom Ausgangspunkt hab ich nichts geschrieben, der fällt bei mir genauso wie bei dir vom Himmel.
Und noch ein Nachtrag: Die Seite http://cdecl.ridiculousfish.com/ kann zwar nur Variablen und keine Funktionssignaturen entziffern, aber ist hier wohl trotzdem relevant.
Stimmt nicht. Was die nicht können sind benannte Funktionsparameter. Damit gehts: void (*signal(int, void (*)(int)))(int)
-
Bashar schrieb:
SeppJ schrieb:
Bashar schrieb:
Von innen nach außen unter Berücksichtigung der Operatorenrangfolge und -assoziativität:
Das wollte ich zunächst auch so schreiben, aber ich finde das äußerst missverständlich. "Innen" ist hier letztlich func. Und das ist ein schlechter Anfangspunkt, um den Ausdruck zu entziffern.
Du hast es doch auch von innen nach außen gemacht, volkard auch. Geht auch nicht anders. Vom Ausgangspunkt hab ich nichts geschrieben, der fällt bei mir genauso wie bei dir vom Himmel.
Nein, er fällt nicht vom Himmel. Es ist der erste Bezeichner. Bei dir klingt das so, als solle man ganz innen anfangen, da habe ich dich wohl missverstanden. Aber ich bin immer erst nach außen gegangen und dann nach innen. Das ist genau so gut zu rechtfertigen, wie anders herum. Das allerletzte was ich zugefügt habe ist der int mit den meisten Klammern drumrum.
Und noch ein Nachtrag: Die Seite http://cdecl.ridiculousfish.com/ kann zwar nur Variablen und keine Funktionssignaturen entziffern, aber ist hier wohl trotzdem relevant.
Stimmt nicht. Was die nicht können sind benannte Funktionsparameter. Damit gehts: void (*signal(int, void (*)(int)))(int)
Gut zu wissen. Darum hat das bei mir nie funktioniert. Wie ironisch, da doch C im Gegensatz zu C++ vorschreibt, dass man Funktionsparameter benennen muss.
-
SeppJ schrieb:
Bashar schrieb:
SeppJ schrieb:
Bashar schrieb:
Von innen nach außen unter Berücksichtigung der Operatorenrangfolge und -assoziativität:
Das wollte ich zunächst auch so schreiben, aber ich finde das äußerst missverständlich. "Innen" ist hier letztlich func. Und das ist ein schlechter Anfangspunkt, um den Ausdruck zu entziffern.
Du hast es doch auch von innen nach außen gemacht, volkard auch. Geht auch nicht anders. Vom Ausgangspunkt hab ich nichts geschrieben, der fällt bei mir genauso wie bei dir vom Himmel.
Nein, er fällt nicht vom Himmel. Es ist der erste Bezeichner.
Das stimmt hier zwar, kann aber nur eine Daumenregel und nicht die tatsächliche Regel sein, da der Bezeichner fehlen kann, z.B. in einem Cast-Ausdruck:
(void (*(int, void (*)(int)))(int)) p
-
ridiculousfishs cdecl kommt mit mehr nicht zurecht.
Z.B. Ellipsen, oder um mal beim Thema zu bleiben, einer alternativen Funktionszeigerschreibweise ohne Sternchen:
void f(void (void)); // oder anhand des Beispiels void (*signal(int, void (int)))(int);
Oder C99. Und damit meine ich nicht mal so etwas exotisches:
void g(int [static 4]); void h(int [const]);
-
Bashar schrieb:
SeppJ schrieb:
Nein, er fällt nicht vom Himmel. Es ist der erste Bezeichner.
Das stimmt hier zwar, kann aber nur eine Daumenregel und nicht die tatsächliche Regel sein, da der Bezeichner fehlen kann, z.B. in einem Cast-Ausdruck:
(void (*(int, void (*)(int)))(int)) p
Das ist schon die Regel für den Startpunkt, sofern sie anwendbar ist. Dahinter steckt natürlich irgendwo die Syntax der Sprache C, aus der man diese Regel herleiten kann. Wenn wir streng nach der Syntax, wie sie im Standard definiert wird, vorgehen, dann haben wir auch die Wahl, von Innen oder von Außen anzufangen, je nachdem, welche Art von Parser wir für die Grammatik nutzen wollen. Hier ist dann sogar wirklich von ganz Innen bzw. ganz außen gemeint:
(void ((int, void ()(int)))(int)) // Wir erkennen an den umschließenden Klammern, dass es um einen Cast geht, die Klammern selber sind aber nicht weiter von Belangvoid // irgendwas void-artiges void (* )( ) // Aha: Ein Zeiger auf eine void-Funktion (Dies könnte prinzipiell auch eine Funktion sein, die eine Funktion zurück gibt. Da das aber nicht erlaubt ist, lese ich den Stern gleich hier.) void (* )(int) // Die void-Funktion nimmt einen int void (*( ))(int) // Der Zeiger ist selber Rückgabe einer Funktion void (*(int, void ))(int) // Letztere Funktion nimmt einen int und etwas void-artiges void (*(int, void (*)( )))(int) // Siehe oben: Das void-Ding ist ein Zeiger auf eine void-Funktion void (*(int, void (*)(int)))(int) // mit int als parameter
oder
int // ein int (int) // der Argument von etwas ist (*)(int) // Der int ist Argument eines Funktionszeigers void (*)(int) // Diese Funktion gibt void zurück int, void (*)(int) // auf gleicher Ebene ist auch ein int (int, void (*)(int)) // Beide sind Argumente einer Funktion *(int, void (*)(int)) // auf die gezeigt wird (*(int, void (*)(int)))( ) // von einer anderen Funktion void (*(int, void (*)(int)))(int) // mit void als Rückgabe und int als Argument
Wobei mir die erste Methode intuitiver ist. Man sieht auch bei der letzten Zeile des zweiten Beispiels, dass ist im Prinzip zum int-Argument wieder abgestiegen bin. Außerdem ändert sich ständig der Basistyp. Oben ist von vornherein klar, dass am Ende irgendwie ein void (mit massiven Modifikationen) raus kommt, das bleibt auch die ganze Zeit so. Beim zweiten Beispiel erfährt man das erst ganz am Ende. Und man kann prinzipiell Mehrdeutigkeiten haben, wo "Innen" ist. Nein, die zweite Methode mag ich nicht.
Ich kenne mich nicht gut genug mit Informatik aus, um zu sagen, ob es noch gemischte Parser für diese Art von Grammatik gibt. Ich kann nur von oben nach unten oder von unten nach oben durch die Ausdrücke gehen
.
-
SeppJ schrieb:
Das ist schon die Regel für den Startpunkt, sofern sie anwendbar ist.
Was genau meinst du mit die Regel? Eine die zufällig für alle anwendbaren Fälle zutrifft, oder gibt es noch andere Kriterien?
-
Eine die
zufälligfür alle anwendbaren Fälle zutrifft.
-
OK, dann haben wir ja nichts inhaltliches zu diskutieren.