1. Was ist eine Callback-Funktion?

Callback-Funktionen klingen schon vom Namen her beeindruckender als gewöhnliche Funktionen. Was genau ist also eine Callback-Funktion? Verzeihen Sie mir, dass ich nicht viele Bücher gelesen habe; ich habe in keinem Buch eine Definition von Callback-Funktionen gesehen. Ich habe auf Baidu gesucht und eine Vielzahl unterschiedlicher Meinungen gefunden. Ein großer Teil verwendet ein Szenario wie dieses zur Erklärung: Person A geht zum Laden von Person B, um etwas zu kaufen, aber es ist zufällig nicht auf Lager. Person A hinterlässt bei Person B ihre Nummer, und Person B benachrichtigt Person A, wenn es wieder auf Lager ist. Das lässt die Leute eher an asynchrone Operationen als an Callbacks denken. Es gibt auch zwei englische Ausdrücke, die mir tiefen Eindruck hinterlassen haben: 1) Wenn du mich anrufst, rufe ich dich zurück; 2) Ruf mich nicht an, ich rufe dich an. Sie scheinen Sinn zu ergeben, aber wenn man genauer darüber nachdenkt: Können gewöhnliche Funktionen nicht auch diese beiden Punkte erfüllen? Deshalb halte ich diese Aussagen für nicht ganz treffend, weil sie die Eigenschaften von Callback-Funktionen nicht ausdrücken, das heißt, sie zeigen nicht den Unterschied zwischen ihnen und gewöhnlichen Funktionen. Allerdings finde ich die Erklärung von Baidu Baike recht gut (obwohl ich mich oft über Baidu Search beschwere ...): Eine Callback-Funktion ist eine Funktion, die über einen Funktionszeiger aufgerufen wird. Wenn Sie den Zeiger (die Adresse) einer Funktion als Parameter an eine andere Funktion übergeben und wenn dieser Zeiger verwendet wird, um die Funktion aufzurufen, auf die er zeigt, sagen wir, dies ist eine Callback-Funktion.

Lassen Sie mich zunächst meine Sichtweise darlegen. Wir können den Begriff wörtlich zerlegen. Für "Callback-Funktion" (callback function) kann er im Chinesischen tatsächlich auf zwei Arten verstanden werden: 1) die Funktion, die zurückgerufen wird; 2) die Funktion, die sich umdreht, um den Aufruf durchzuführen. Was zum Teufel ist also dieses "sich umdrehen, um aufzurufen"?

Schauen wir uns zunächst Wikipedias Analyse von Callbacks an: In der Computerprogrammierung ist ein Callback jeglicher ausführbarer Code, der als Argument an anderen Code übergeben wird und von dem erwartet wird, dass er das Argument zu einem bestimmten Zeitpunkt zurückruft (ausführt). Diese Ausführung kann sofort erfolgen, wie bei einem synchronen Callback, oder sie kann zu einem späteren Zeitpunkt erfolgen, wie bei einem asynchronen Callback. Mit anderen Worten: Ausführbarer Code wird wie ein Parameter an anderen Code übergeben, und dieser Code wird irgendwann aufgerufen und ausgeführt; das nennt man einen Callback. Wird der Code sofort ausgeführt, nennt man ihn einen synchronen Callback; wird er zu einem späteren Zeitpunkt ausgeführt, nennt man ihn einen asynchronen Callback. Auf Synchronität und Asynchronität gehen wir hier nicht ein; bitte ziehen Sie relevante Materialien heran.

Schauen wir uns nun eine prägnante und klare Aussage eines Experten auf Stack Overflow an:Ein "Callback" ist jede Funktion, die von einer anderen Funktion aufgerufen wird, welche die erste Funktion als Parameter entgegennimmt. Mit anderen Worten: Wenn Funktion F1 Funktion F2 aufruft, übergibt Funktion F1 den Zeiger einer anderen Funktion F3 als Parameter an Funktion F2. Während der Ausführung von Funktion F2 ruft Funktion F2 Funktion F3 auf. Diese Aktion wird als Callback bezeichnet, und die Funktion F3, die zuerst als Zeiger übergeben und später zurückgerufen wurde, ist die Callback-Funktion. Inzwischen sollten Sie die Definition einer Callback-Funktion verstehen, oder?

2. Warum Callback-Funktionen verwenden?

Viele Freunde fragen sich vielleicht, warum nicht einfach der Funktionsname direkt an der Callback-Stelle geschrieben wird, wie bei gewöhnlichen Funktionsaufrufen? Würde das nicht auch funktionieren? Warum müssen wir Callback-Funktionen verwenden? Es ist gut, diesen Gedanken zu haben, denn viele Beispiele zur Erklärung von Callback-Funktionen, die man online findet, können tatsächlich vollständig mit gewöhnlichen Funktionsaufrufen umgesetzt werden. Um diese Frage zu beantworten, wollen wir zunächst den Nutzen und Zweck von Callback-Funktionen verstehen, und das ist Entkopplung. Ja, so einfach ist die Antwort. Genau wegen dieser Eigenschaft können gewöhnliche Funktionen Callback-Funktionen nicht ersetzen. In meinen Augen ist dies also das größte Merkmal von Callback-Funktionen. Schauen wir uns ein Bild auf Wikipedia an, das meiner Meinung nach sehr gut gezeichnet ist.

Unten ist ein unvollständiger Ausschnitt aus C-Code, um die Bedeutung des obigen Diagramms zu veranschaulichen:

Beispiel

#include<stdio.h>
#include<softwareLib.h> // Header-Datei der Software-Bibliothek einbinden, in der sich die Bibliotheksfunktion befindet

int Callback() // Callback-Funktion
{
    // TODO
    return 0;
}
int main() // Hauptprogramm
{
    // TODO
    Library(Callback);
    // TODO
    return 0;
}

Auf den ersten Blick scheint ein Callback nur ein Aufruf zwischen Funktionen zu sein, nicht anders als gewöhnliche Funktionsaufrufe. Bei genauerem Hinsehen lässt sich jedoch ein entscheidender Unterschied feststellen: Bei einem Callback übergibt das Hauptprogramm die Callback-Funktion wie einen Parameter an die Bibliotheksfunktion. Auf diese Weise können wir, solange wir die an die Bibliotheksfunktion übergebenen Parameter ändern, unterschiedliche Funktionalität implementieren. Fühlt sich das nicht sehr flexibel an? Und die Implementierung der Bibliotheksfunktion muss überhaupt nicht geändert werden. Das ist Entkopplung. Schauen wir genauer hin: Die Hauptfunktion und die Callback-Funktion befinden sich auf derselben Ebene, während die Bibliotheksfunktion auf einer anderen Ebene liegt. Denken Sie darüber nach: Wenn die Bibliotheksfunktion für uns nicht sichtbar ist, können wir ihre Implementierung nicht ändern, was bedeutet, dass wir die Bibliotheksfunktion nicht so ändern können, dass sie gewöhnliche Funktionen aufruft. Dann können wir dies nur erreichen, indem wir unterschiedliche Callback-Funktionen übergeben. Dies ist auch eine häufige Situation im Arbeitsalltag. Wenn wir nun main(), Library() und Callback() zurück auf die früheren Funktionen F1, F2 und F3 abbilden, ist es dann nicht klarer?

Nachdem Sie nun die Eigenschaften von Callback-Funktionen verstanden haben, können Sie ungefähr erkennen, wann sie verwendet werden sollten? Richtig, Sie können Callback-Funktionen an vielen Stellen verwenden, um gewöhnliche Funktionsaufrufe zu ersetzen, aber meiner Meinung nach sollten Callback-Funktionen verwendet werden, wenn Sie die Kopplung reduzieren müssen.

3. Wie verwendet man Callback-Funktionen?

Nachdem Sie nun wissen, was eine Callback-Funktion ist, und ihre Eigenschaften verstanden haben, wie sollten Sie Callback-Funktionen verwenden? Schauen wir uns unten einen einfachen, ausführbaren Code für eine synchrone Callback-Funktion an.

Beispiel

#include<stdio.h>

int Callback_1() // Callback-Funktion 1
{
    printf("Hallo, dies ist Callback_1 ");
    return 0;
}

int Callback_2() // Callback-Funktion 2
{
    printf("Hallo, dies ist Callback_2 ");
    return 0;
}

int Callback_3() // Callback-Funktion 3
{
    printf("Hallo, dies ist Callback_3 ");
    return 0;
}

int Handle(int (*Callback)())
{
    printf("Betreten der Handle-Funktion. ");
    Callback();
    printf("Verlassen der Handle-Funktion. ");
}

int main()
{
    printf("Betreten der Main-Funktion. ");
    Handle(Callback_1);
    Handle(Callback_2);
    Handle(Callback_3);
    printf("Verlassen der Main-Funktion. ");
    return 0;
}

Ausgabe:

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3
Leaving Handle Function.
Leaving Main Function.

Wie Sie sehen können, ist der Parameter in der Funktion Handle() ein Zeiger. Wenn die Funktion Handle() in der Funktion main() aufgerufen wird, werden ihr die Funktionsnamen Callback_1()/Callback_2()/Callback_3() übergeben. An diesem Punkt ist der Funktionsname der Zeiger auf die entsprechende Funktion. Mit anderen Worten: Eine Callback-Funktion ist tatsächlich eine Verwendung von Funktionszeigern. Lesen Sie nun diesen Satz noch einmal: Ein "Callback" ist jede Funktion, die von einer anderen Funktion aufgerufen wird, die die erste Funktion als Parameter entgegennimmt. Ist es jetzt nicht klarer?

4. Wie verwendet man Callback-Funktionen mit Parametern?

Aufmerksame Leser haben vielleicht bemerkt, dass die Callback-Funktionen in den vorherigen Beispielen keine Parameter haben. Können wir also Funktionen mit Parametern als Callback aufrufen? Die Antwort ist ja. Wie rufen wir sie dann auf? Wir können das obige Beispiel einfach ein wenig ändern:

Beispiel

#include<stdio.h>

int Callback_1(int x) // Callback-Funktion 1
{
    printf("Hallo, dies ist Callback_1: x = %d ", x);
    return 0;
}

int Callback_2(int x) // Callback-Funktion 2
{
    printf("Hallo, dies ist Callback_2: x = %d ", x);
    return 0;
}

int Callback_3(int x) // Callback-Funktion 3
{
    printf("Hallo, dies ist Callback_3: x = %d ", x);
    return 0;
}

int Handle(int y, int (*Callback)(int))
{
    printf("Betreten der Handle-Funktion. ");
    Callback(y);
    printf("Verlassen der Handle-Funktion. ");
}

int main()
{
    int a = 2;
    int b = 4;
    int c = 6;
    printf("Betreten der Main-Funktion. ");
    Handle(a, Callback_1);
    Handle(b, Callback_2);
    Handle(c, Callback_3);
    printf("Verlassen der Main-Funktion. ");
    return 0;
}

Ausgabe:

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1: x = 2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2: x = 4
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3: x = 6
Leaving Handle Function.
Leaving Main Function.

Wie Sie sehen, ist es nicht so einfach, int Handle(int (*Callback)()) direkt in int Handle(int (*Callback)(int)) zu ändern. Stattdessen müssen Sie einen zusätzlichen Parameter hinzufügen, um den Parameterwert der Callback-Funktion zu speichern, wie den Parameter y in int Handle(int y, int (*Callback)(int)) hier. Ähnlich können Callback-Funktionen mit mehreren Parametern verwendet werden.

URL des Originalartikels: https://www.cnblogs.com/jiangzhaowei/p/9129105.html