Frage

Von der Lesung, die ich getan habe, setzt Core Audio stark auf Rückrufe (und C ++, aber das ist eine andere Geschichte).

Ich verstehe das Konzept (Art) von einer Funktion der Einrichtung, die durch eine andere Funktion aufgerufen wird wiederholt, um eine Aufgabe zu erfüllen. Ich verstehe einfach nicht, wie sie eingerichtet bekommen und wie sie tatsächlich arbeiten. Alle Beispiele würden geschätzt.

War es hilfreich?

Lösung

Es gibt keine „Rückruf“ in C -. Nicht mehr als jedes anderen generischen Programmierkonzept

Sie sind mit Funktionszeigern implementiert. Hier ein Beispiel:

void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i<arraySize; i++)
        array[i] = getNextValue();
}

int getNextRandomValue(void)
{
    return rand();
}

int main(void)
{
    int myarray[10];
    populate_array(myarray, 10, getNextRandomValue);
    ...
}

Hier nimmt die populate_array Funktion einen Funktionszeiger als dritter Parameter, und nennt es um die Werte zu erhalten, um das Array zu füllen mit. Wir haben den Rückruf getNextRandomValue geschrieben, die einen Zufalls-ish Wert zurückgibt, und übergeben einen Zeiger darauf populate_array. populate_array wird unser Callback-Funktion 10 Mal aufrufen und die zurückgegebenen Werte für die Elemente in der angegebenen Array zugeordnet werden.

Andere Tipps

Hier ist ein Beispiel für Rückrufe in C.

Angenommen, Sie haben einen Code schreiben möchten, die Rückrufe ermöglicht Registrierung aufgerufen werden, wenn ein Ereignis auftritt.

Sie zuerst die Art der Funktion für den Rückruf verwendet definieren:

typedef void (*event_cb_t)(const struct event *evt, void *userdata);

Nun definiert eine Funktion, die verwendet wird, einen Rückruf zu registrieren:

int event_cb_register(event_cb_t cb, void *userdata);

Dies ist, was Code würde so aussehen einen Rückruf registriert:

static void my_event_cb(const struct event *evt, void *data)
{
    /* do stuff and things with the event */
}

...
   event_cb_register(my_event_cb, &my_custom_data);
...

In dem Interna des Event-Dispatcher kann der Rückruf in einer Struktur gespeichert werden, die etwa wie folgt aussieht:

struct event_cb {
    event_cb_t cb;
    void *data;
};

Dies ist, was der Code wie folgt aussieht, dass ein Rückruf ausführt.

struct event_cb *callback;

...

/* Get the event_cb that you want to execute */

callback->cb(event, callback->data);

Ein einfacher Anruf zurück Programm. Hoffe, es beantwortet Ihre Frage.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "../../common_typedef.h"

typedef void (*call_back) (S32, S32);

void test_call_back(S32 a, S32 b)
{
    printf("In call back function, a:%d \t b:%d \n", a, b);
}

void call_callback_func(call_back back)
{
    S32 a = 5;
    S32 b = 7;

    back(a, b);
}

S32 main(S32 argc, S8 *argv[])
{
    S32 ret = SUCCESS;

    call_back back;

    back = test_call_back;

    call_callback_func(back);

    return ret;
}

A Callback-Funktion in C ist die äquivalent ein Funktionsparameter / Variablen zugewiesen innerhalb einer anderen Funktion verwendet werden. Wiki Beispiel

Im folgenden Code

#include <stdio.h>
#include <stdlib.h>

/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
    printf("%d and %d\n", numberSource(), numberSource());
}

/* A possible callback */
int overNineThousand(void) {
    return (rand() % 1000) + 9001;
}

/* Another possible callback. */
int meaningOfLife(void) {
    return 42;
}

/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
    PrintTwoNumbers(&rand);
    PrintTwoNumbers(&overNineThousand);
    PrintTwoNumbers(&meaningOfLife);
    return 0;
}

Die Funktion (* numberSource) innerhalb des Funktionsaufruf PrintTwoNumbers ist eine Funktion „Rückruf“ / Ausführen von innen PrintTwoNumbers wie durch den Code bestimmt, wie es läuft.

Wenn Sie also so etwas wie eine Pthread Funktion haben eine andere Funktion zuweisen konnte innerhalb der Schleife von seiner Instantiierung auszuführen.

Rückrufe in C sind in der Regel unter Verwendung von Funktionszeigern und einen zugehörigen Datenzeiger implementiert. Sie geben Ihre Funktion on_event() und Datenzeiger auf eine Rahmenfunktion watch_events() (zum Beispiel). Wenn ein Ereignis eintritt, wird Ihre Funktion mit Ihren Daten und einige ereignisspezifische Daten bezeichnet.

Rückrufe werden auch in GUI-Programmierung verwendet. Die GTK + Tutorial hat einen schönen Abschnitt auf der Theorie der Signale und Rückrufe

Das Wikipedia-Artikel hat ein Beispiel in C.

Ein gutes Beispiel dafür ist, dass neuer Module das Apache Web-Server-Register mit dem Haupt-Apache-Prozess verstärken geschrieben von ihnen Funktionszeiger vorbei so dass diese Funktionen wieder zu Prozess Webseite Anfragen genannt werden.

Ein Rückruf in C ist eine Funktion, die zu einem bestimmten Zeitpunkt auf eine andere Funktion zu „Rückruf“ zur Verfügung gestellt wird, wenn die andere Funktion seine Aufgabe tut.

Es gibt zwei Möglichkeiten, dass ein Rückruf verwendet wird : synchrone und asynchrone Callback Rückrufen. Ein synchroner Rückruf wird an eine andere Funktion zur Verfügung gestellt, die eine bestimmte Aufgabe tun wird und dann an den Aufrufer zurückgeben mit der Aufgabe abgeschlossen. Ein asynchroner Rückruf an einem anderen Funktion zur Verfügung gestellt wird, die eine Aufgabe beginnen wird und dann mit der Aufgabe an den Aufrufer zurückgeben beendet möglicherweise nicht.

Ein synchroner Rückruf wird in der Regel einen Delegaten an eine andere Funktion, auf die die andere Funktion überträgt einen Teil Schritt der Aufgabe zu schaffen, verwendet. Klassische Beispiele dieser Delegation sind die Funktionen bsearch() und qsort() aus dem C Standard Library. Beide Funktionen nehmen einen Rückruf, die während der Aufgabe verwendet wird, wird die Funktion bereitstellt, so dass die Art der Daten gesucht wird, im Falle von bsearch() oder sortiert, im Falle von qsort(), braucht nicht durch die bekannt sein Funktion verwendet wird.

Zum Beispiel hier ist ein kleines Beispielprogramm mit bsearch() unterschiedlichen Vergleichsfunktionen, synchron Rückrufe. Dadurch, dass wir die Daten Vergleich zu einer Callback-Funktion übertragen, ermöglicht die bsearch() Funktion uns zur Laufzeit, welche Art von Vergleich wollen wir nutzen, um zu entscheiden. Dies ist synchron, weil, wenn die bsearch() Funktion gibt die Aufgabe abgeschlossen ist.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int iValue;
    int kValue;
    char label[6];
} MyData;

int cmpMyData_iValue (MyData *item1, MyData *item2)
{
    if (item1->iValue < item2->iValue) return -1;
    if (item1->iValue > item2->iValue) return 1;
    return 0;
}

int cmpMyData_kValue (MyData *item1, MyData *item2)
{
    if (item1->kValue < item2->kValue) return -1;
    if (item1->kValue > item2->kValue) return 1;
    return 0;
}

int cmpMyData_label (MyData *item1, MyData *item2)
{
    return strcmp (item1->label, item2->label);
}

void bsearch_results (MyData *srch, MyData *found)
{
        if (found) {
            printf ("found - iValue = %d, kValue = %d, label = %s\n", found->iValue, found->kValue, found->label);
        } else {
            printf ("item not found, iValue = %d, kValue = %d, label = %s\n", srch->iValue, srch->kValue, srch->label);
        }
}

int main ()
{
    MyData dataList[256] = {0};

    {
        int i;
        for (i = 0; i < 20; i++) {
            dataList[i].iValue = i + 100;
            dataList[i].kValue = i + 1000;
            sprintf (dataList[i].label, "%2.2d", i + 10);
        }
    }

//  ... some code then we do a search
    {
        MyData srchItem = { 105, 1018, "13"};
        MyData *foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_iValue );

        bsearch_results (&srchItem, foundItem);

        foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_kValue );
        bsearch_results (&srchItem, foundItem);

        foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_label );
        bsearch_results (&srchItem, foundItem);
    }
}

Ein asynchroner Rückruf, dass anders ist, wenn die aufgerufene Funktion, auf die wir einen Rückruf zurückkehrt bereitzustellen, kann nicht die Aufgabe abgeschlossen sein. Diese Art von Rückruf oft mit asynchronen I / O in dem eine I / O-Operation verwendet wird, gestartet wird und dann, wenn es abgeschlossen ist, wird der Rückruf aufgerufen wird.

Im folgende Programm erstellen wir eine Buchse für TCP-Verbindungsanforderungen zu hören und wenn eine Anforderung empfangen wird, wird die Funktion tut das hört dann die Callback-Funktion aufruft, zur Verfügung gestellt. Diese einfache Anwendung kann durch Ausführen es in einem Fenster ausgeübt werden, während mit der telnet Dienstprogramm oder einem Web-Browser in einem anderen Fenster, eine Verbindung herzustellen.

Ich hob den größten Teil des WinSock-Code aus dem Beispiel Microsoft unter accept() Funktion bietet = "https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs .85) .aspx“rel = "nofollow noreferrer"> https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526 (v = VS.85) aspx

startet diese Anwendung eine listen() auf dem lokalen Rechner, 127.0.0.1, Port 8282 so können Sie entweder telnet 127.0.0.1 8282 oder http://127.0.0.1:8282/ verwenden.

Diese Beispielanwendung wurde als Konsolenanwendung mit Visual Studio 2017 Community Edition erstellt, und es wird die Microsoft WinSock Version von Sockets. Für eine Linux-Anwendung müßten die WinSock-Funktionen mit den Linux-Alternativen und der Windows-Thread-Bibliothek ersetzt werden würde, anstatt pthreads verwenden.

#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>

#include <Windows.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

// function for the thread we are going to start up with _beginthreadex().
// this function/thread will create a listen server waiting for a TCP
// connection request to come into the designated port.
// _stdcall modifier required by _beginthreadex().
int _stdcall ioThread(void (*pOutput)())
{
    //----------------------
    // Initialize Winsock.
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        printf("WSAStartup failed with error: %ld\n", iResult);
        return 1;
    }
    //----------------------
    // Create a SOCKET for listening for
    // incoming connection requests.
    SOCKET ListenSocket;
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port for the socket that is being bound.
    struct sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(8282);

    if (bind(ListenSocket, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR) {
        printf("bind failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Listen for incoming connection requests.
    // on the created socket
    if (listen(ListenSocket, 1) == SOCKET_ERROR) {
        printf("listen failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Create a SOCKET for accepting incoming requests.
    SOCKET AcceptSocket;
    printf("Waiting for client to connect...\n");

    //----------------------
    // Accept the connection.
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        printf("accept failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    else
        pOutput ();   // we have a connection request so do the callback

    // No longer need server socket
    closesocket(ListenSocket);

    WSACleanup();
    return 0;
}

// our callback which is invoked whenever a connection is made.
void printOut(void)
{
    printf("connection received.\n");
}

#include <process.h>

int main()
{
     // start up our listen server and provide a callback
    _beginthreadex(NULL, 0, ioThread, printOut, 0, NULL);
    // do other things while waiting for a connection. In this case
    // just sleep for a while.
    Sleep(30000);
}

In der Regel kann dies durch Verwendung eines Funktionszeigers erfolgen, dh eine spezielle Variable, die auf die Speicherstelle einer Funktion verweist. Sie können diese dann verwenden Sie die Funktion mit bestimmten Argumenten zu nennen. So wird es wahrscheinlich eine Funktion sein, die die Callback-Funktion setzt. Dies wird einen Funktionszeiger akzeptieren und speichern Sie dann die Adresse irgendwo, wo es verwendet werden kann. Danach, wenn das angegebene Ereignis ausgelöst wird, wird es diese Funktion aufrufen.

Es ist viel einfacher, eine Idee, durch Beispiel zu verstehen. Was über Callback-Funktion in C mitgeteilt wurde, sind bisher große Antworten, aber wahrscheinlich ist der größte Vorteil der Funktion des mit dem Code sauber und ordentlich zu halten.

Beispiel

Der folgende C-Code implementiert schnelle Sortierung. Die interessanteste Zeile im Code unten ist dieser, wo wir die Callback-Funktion in Aktion sehen können:

qsort(arr,N,sizeof(int),compare_s2b);

Die compare_s2b ist der Name der Funktion, die qsort () wird unter Verwendung der Funktion aufzurufen. Dies hält qsort () so übersichtlich (daher leichter zu pflegen). Sie rufen eine Funktion mit Namen aus dem Innern einer anderen Funktion (natürlich die Funktionsprototyp Erklärung, zumindest muss precde, bevor sie von einer anderen Funktion aufgerufen werden kann).

Der vollständige Code

#include <stdio.h>
#include <stdlib.h>

int arr[]={56,90,45,1234,12,3,7,18};
//function prototype declaration 

int compare_s2b(const void *a,const void *b);

int compare_b2s(const void *a,const void *b);

//arranges the array number from the smallest to the biggest
int compare_s2b(const void* a, const void* b)
{
    const int* p=(const int*)a;
    const int* q=(const int*)b;

    return *p-*q;
}

//arranges the array number from the biggest to the smallest
int compare_b2s(const void* a, const void* b)
{
    const int* p=(const int*)a;
    const int* q=(const int*)b;

    return *q-*p;
}

int main()
{
    printf("Before sorting\n\n");

    int N=sizeof(arr)/sizeof(int);

    for(int i=0;i<N;i++)
    {
        printf("%d\t",arr[i]);
    }

    printf("\n");

    qsort(arr,N,sizeof(int),compare_s2b);

    printf("\nSorted small to big\n\n");

    for(int j=0;j<N;j++)
    {
        printf("%d\t",arr[j]);
    }

    qsort(arr,N,sizeof(int),compare_b2s);

    printf("\nSorted big to small\n\n");

    for(int j=0;j<N;j++)
    {
        printf("%d\t",arr[j]);
    }

    exit(0);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top