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: foo
wird 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
foo
wird implizit in einen Zeiger auf sich selbst konvertiert und der erste *
wird auf diesen Funktionszeiger angewendet, wodurch die Funktion foo
erneut 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
foo
wird implizit in einen Zeiger auf sich selbst konvertiert; Das Unäre *
wird angewendet und gibt foo
wieder nach.
- Dann wird das auf
&
angewendet foo
, was einen Zeiger auf foo
ergibt, 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 &&foo
funktioniert es nicht: &foo
ist keine Funktion; Es ist ein Funktionszeiger, der ein Wert ist. Dies &*&*&*&*&*&*foo
würde jedoch genauso funktionieren, &******&foo
da 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.
&foo
nimmt die Adresse vonfoo
, was dazu führt, dass ein Funktionszeigerfoo
wie erwartet auf zeigt.