Ich bin relativ neu in C und fand es faszinierend, dass beide der folgenden Aufrufe an den Funktionszeiger kompilieren und gut funktionieren. Eins mit und ohne Dereferenzierung des Funktionszeigers vor dem Aufruf.
%Vor% Ich glaube, ich verstehe, dass (*f)()
der "offizielle" Weg ist, einen Funktionszeiger aufzurufen, aber warum funktioniert f()
einfach? Ist das syntaktischer Zucker der letzten C-Versionen?
Dies ist ein Stück syntaktischer / semantischer Zucker, der, AFAIK, seit den allerersten Versionen von C funktioniert. Es macht Sinn, wenn Sie Funktionen als Zeiger auf Code denken.
Die einzige spezielle Regel, die benötigt wird, um Funktionszeiger so zu machen, besteht darin, dass das Umleiten eines Funktionszeigers den gleichen Zeiger zurück gibt (weil Sie Code in Standard C sowieso nicht manipulieren können): wenn f
ein Funktionszeiger ist, dann f == (*f) == (**f)
, usw.
(Abgesehen davon, dass Sie mit einer Deklaration wie void (*f)()
aufpassen. Eine leere Argumentliste bezeichnet eine alte Deklaration vor C89, die nur auf den Rückgabetyp passt. Lieber void (*f)(void)
für die Typensicherheit bevorzugen.)
Ein Funktionsaufruf-Ausdruck hat immer die Form "Funktionszeiger", "runde Klammer", "Argumente", "runde Klammer". Damit Sie (&printf)("Hello World\n")
nicht jedes Mal 1 buchstabieren müssen, gibt es eine separate Regel, nach der ein Ausdruck, der eine Funktion kennzeichnet, in den jeweiligen Funktionszeiger abfällt.
Da ein Funktionszeiger dereferenziert werden kann, um einen Ausdruck zu geben, der eine Funktion wieder kennzeichnet, wird dieser wieder abklingen, so dass Sie weiterhin Dereferenzierung vornehmen können und es wird viel Zerfall geben:
%Vor%
1) Frühe Perl hat Funktionssyntax wie diese.
Der C 2011-Standard sagt in Abschnitt 6.3.2.1, Absatz 4:
Wenn es sich nicht um den Operanden des Operators sizeof , den Operator _Alignof oder den unären Operator & amp; handelt type '' function returning type '' wird in einen Ausdruck konvertiert, der den Typ '' Zeiger auf Funktion hat und type 'zurückgibt.
Das heißt, wenn f
eine Funktion angibt, wird f()
in einem Aufruf wie f
automatisch in &f
konvertiert, was zu (&f)()
führt. Dies ist eigentlich der "richtige" Weg, eine Funktion aufzurufen, weil der Funktionsaufruf-Ausdruck einen Zeiger auf eine Funktion benötigt.
Überlege jetzt, was in *f
passiert. Der f
wird automatisch in &f
konvertiert, also haben wir *&f
. In diesem Ausdruck ist das Ergebnis des Operators *
eine Funktion, f
; es kehrt nur die Operation um, die von &
ausgeführt wird. Also *&f
ist gleich wie f
. Wir können das auf unbestimmte Zeit wiederholen: **f
wird automatisch in **&f
konvertiert, was *f
ist, was automatisch in *&f
konvertiert wird, was f
ist, was automatisch in &f
konvertiert wird.
In C können Sie Ihre Funktion wie folgt aufrufen:
%Vor% alle sind gültig. In C wird die Dereferenzierung oder die Übernahme der Adresse einer Funktion nur zu einem Zeiger auf diese Funktion ausgewertet, und die Dereferenzierung eines Funktionszeigers wird nur zurück zum Funktionszeiger ausgewertet. C ist so konzipiert, dass sowohl der Name des Funktionsnamens als auch der Zeiger der Variablenhaltefunktion dasselbe bedeuten: Adresse zum CODE-Speicher . Und es ermöglicht, zu diesem Speicher zu springen, indem Sie die Syntax ()
entweder für einen Bezeichner oder eine Variable verwenden.
Und der letzte, aber am wenigsten Standard sagt das:
4 Ein Funktionsbezeichner ist ein Ausdruck mit einem Funktionstyp. Außer wenn es das ist Operand des Operators
sizeof
, der Operator_Alignof
, 65) oder der Operator uny&
, a function designator mit dem Typ '' function returning type '' wird in einen Ausdruck konvertiert, der den Typ '' pointer to function returning type '' hat.
Tags und Links c