Es gibt einige Teile, mit denen alle diese Operatorkombinationen auf die gleiche Weise funktionieren können.
Der grundlegende Grund, warum all diese Arbeiten funktionieren, ist, dass eine Funktion (wie foo) implizit in einen Zeiger auf die Funktion konvertierbar ist. Aus diesem Grund void (*p1_foo)() = foo;funktioniert works: foowird implizit in einen Zeiger auf sich selbst konvertiert und dieser Zeiger wird zugewiesen p1_foo.
Das Unäre &liefert, wenn es auf eine Funktion angewendet wird, einen Zeiger auf die Funktion, genau wie es die Adresse eines Objekts liefert, wenn es auf ein Objekt angewendet wird. Bei Zeigern auf gewöhnliche Funktionen ist sie aufgrund der impliziten Umwandlung von Funktion in Funktionszeiger immer redundant. In jedem Fall void (*p3_foo)() = &foo;funktioniert dies deshalb .
Das Unäre *ergibt, wenn es auf einen Funktionszeiger angewendet wird, die Funktion, auf die gezeigt wird, genauso wie es das Objekt zeigt, auf das gezeigt wird, wenn es auf einen gewöhnlichen Zeiger auf ein Objekt angewendet wird.
Diese Regeln können kombiniert werden. Betrachten Sie Ihr vorletztes Beispiel **foo:
- Erstens
foowird implizit in einen Zeiger auf sich selbst konvertiert und der erste *wird auf diesen Funktionszeiger angewendet, wodurch die Funktion fooerneut erhalten wird.
- Dann wird das Ergebnis wieder implizit in einen Zeiger auf sich selbst konvertiert und das zweite
*wird angewendet, was wiederum die Funktion ergibt foo.
- Es wird dann implizit wieder in einen Funktionszeiger konvertiert und der Variablen zugewiesen.
Sie können beliebig viele *s hinzufügen , das Ergebnis ist immer das gleiche. Je mehr *s, desto besser.
Wir können auch Ihr fünftes Beispiel betrachten &*foo:
- Erstens
foowird implizit in einen Zeiger auf sich selbst konvertiert; Das Unäre *wird angewendet und gibt foowieder nach.
- Dann wird das auf
&angewendet foo, was einen Zeiger auf fooergibt, der der Variablen zugewiesen ist.
Das &kann jedoch nur auf eine Funktion angewendet werden, nicht auf eine Funktion, die in einen Funktionszeiger konvertiert wurde (es sei denn, der Funktionszeiger ist natürlich eine Variable. In diesem Fall ist das Ergebnis ein Zeiger auf einen Zeiger. zu einer Funktion (zum Beispiel könnten Sie Ihrer Liste hinzufügen void (**pp_foo)() = &p7_foo;).
Deshalb &&foofunktioniert es nicht: &fooist keine Funktion; Es ist ein Funktionszeiger, der ein Wert ist. Dies &*&*&*&*&*&*foowürde jedoch genauso funktionieren, &******&fooda in beiden Ausdrücken das &immer auf eine Funktion und nicht auf einen r-Wert-Funktionszeiger angewendet wird.
Beachten Sie auch, dass Sie das Unary nicht verwenden müssen, *um den Aufruf über den Funktionszeiger zu tätigen. beide (*p1_foo)();und (p1_foo)();haben das gleiche Ergebnis, wiederum aufgrund der Umwandlung von Funktion in Funktionszeiger.
&foonimmt die Adresse vonfoo, was dazu führt, dass ein Funktionszeigerfoowie erwartet auf zeigt.