문제

내가 한 독서에서 Core Audio는 콜백 (및 C ++에 크게 의존하지만 또 다른 이야기입니다).

작업을 수행하기 위해 반복적으로 다른 함수에 의해 호출되는 함수를 설정하는 개념 (일종의)을 이해합니다. 나는 그들이 어떻게 설정되는지와 그들이 실제로 어떻게 작동하는지 이해하지 못합니다. 모든 예는 감사 할 것입니다.

도움이 되었습니까?

해결책

C에서 "콜백"은 없습니다. 다른 일반적인 프로그래밍 개념은 없습니다.

기능 포인터를 사용하여 구현됩니다. 예는 다음과 같습니다.

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);
    ...
}

여기, populate_array 함수는 함수 포인터를 세 번째 매개 변수로 가져 와서 값을 배열로 채우도록 호출합니다. 우리는 콜백을 썼습니다 getNextRandomValue, 임의의 값을 반환하고 포인터를 전달했습니다. populate_array. populate_array 콜백 함수를 10 번 호출하고 주어진 배열의 요소에 반환 된 값을 할당합니다.

다른 팁

다음은 C의 콜백의 예입니다.

일부 이벤트가 발생할 때 콜백 등록을 호출 할 수있는 코드를 작성하고 싶다고 가정 해 봅시다.

먼저 콜백에 사용되는 기능 유형을 정의합니다.

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

이제 콜백을 등록하는 데 사용되는 함수를 정의합니다.

int event_cb_register(event_cb_t cb, void *userdata);

이것이 코드가 콜백을 등록하는 것처럼 보이는 것입니다.

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);
...

이벤트 디스패처 내부에서 콜백은 다음과 같은 모습을 보이는 구조물에 저장 될 수 있습니다.

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

이것이 코드가 콜백을 실행하는 것처럼 보이는 것입니다.

struct event_cb *callback;

...

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

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

간단한 콜백 프로그램. 그것이 당신의 질문에 답하기를 바랍니다.

#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;
}

C의 콜백 함수는 다른 함수 내에서 사용하도록 할당 된 함수 매개 변수 / 변수와 동일합니다.위키 예

아래 코드에서

#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;
}

함수 내부의 함수 (*NumbersOURCE)는 COLL COMB PRINTTWONUMBERS가 코드가 실행될 때 코드에 의해 지시 된대로 "호출" / 실행하는 함수입니다.

따라서 pthread 함수와 같은 것이 있다면 인스턴스화에서 루프 내부에서 실행될 다른 함수를 할당 할 수 있습니다.

C의 콜백은 일반적으로 기능 포인터와 관련 데이터 포인터를 사용하여 구현됩니다. 당신은 당신의 기능을 통과합니다 on_event() 및 프레임 워크 기능에 대한 데이터 포인터 watch_events() (예를 들어). 이벤트가 발생하면 데이터와 일부 이벤트 별 데이터와 함께 기능이 호출됩니다.

콜백은 GUI 프로그래밍에도 사용됩니다. 그만큼 GTK+ 튜토리얼 에 좋은 섹션이 있습니다 신호 및 콜백 이론.

이것 위키 백과 기사 C에 예제가 있습니다.

좋은 예는 기능 포인터를 전달하여 Apache 웹 서버 레지스터를 기본 Apache 프로세스로 보강하기 위해 작성된 새 모듈이 해당 기능을 프로세스 웹 페이지 요청으로 다시 호출합니다.

C의 콜백은 다른 함수가 작업을 수행 할 때 어느 시점에서 "호출"에 다른 함수에 제공되는 함수입니다.

거기 있습니다 콜백이 사용되는 두 가지 방법: 동기 콜백 및 비동기 콜백. 동기식 콜백이 다른 기능에 제공되는 작업을 수행하여 작업을 수행 한 다음 작업이 완료된 상태에서 발신자에게 돌아갑니다. 비동기 콜백은 다른 함수에 제공되어 작업을 시작한 다음 완료되지 않은 작업으로 호출자에게 돌아갑니다.

동기식 콜백은 일반적으로 다른 함수가 작업의 일부 단계를 위임하는 다른 함수에 대한 대의원을 제공하는 데 사용됩니다. 이 대표단의 고전적인 예는 기능입니다 bsearch() 그리고 qsort() C 표준 라이브러리에서. 이 기능은 작업 중에 사용되는 콜백을 취합니다. bsearch(), 또는 정렬 된 경우 qsort(), 사용되는 기능으로 알 필요는 없습니다.

예를 들어 여기에는 작은 샘플 프로그램이 있습니다 bsearch() 다른 비교 함수를 사용하여 동기식 콜백. 데이터 비교를 콜백 함수와 위임 할 수있게함으로써 bsearch() 기능을 사용하면 런타임에 어떤 종류의 비교를 사용하고 싶은지 결정할 수 있습니다. 이것은 때로 동기입니다 bsearch() 함수 작업이 완료되었습니다.

#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);
    }
}

비동기 콜백은 콜백 반환을 제공하는 호출 된 함수가 작업을 완료하지 못할 수 있다는 점에서 다릅니다. 이 유형의 콜백은 종종 I/O 작동이 시작된 다음 완료되면 콜백이 호출되는 비동기 I/O와 함께 사용됩니다.

다음 프로그램에서는 TCP 연결 요청을 듣기 위해 소켓을 만듭니다. 요청이 수신되면 청취를 수행하는 기능이 제공된 콜백 함수를 호출합니다. 이 간단한 응용 프로그램은 telnet 다른 창에 연결하려는 유틸리티 또는 웹 브라우저.

Microsoft가 제공하는 예제에서 대부분의 Winsock 코드를 들어 올렸습니다. accept() 기능 https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx

이 응용 프로그램은 a listen() 로컬 호스트에서 127.0.0.1, 포트 8282를 사용하여 둘 중 하나를 사용할 수 있습니다. telnet 127.0.0.1 8282 또는 http://127.0.0.1:8282/.

이 샘플 응용 프로그램은 Visual Studio 2017 Community Edition을 사용하여 콘솔 애플리케이션으로 만들어졌으며 Microsoft Winsock 버전의 소켓을 사용하고 있습니다. Linux 응용 프로그램의 경우 Winsock 함수는 Linux 대안으로 대체되어야하며 Windows 스레드 라이브러리가 사용할 것입니다. pthreads 대신에.

#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);
}

일반적으로 기능 포인터를 사용하여 수행 할 수 있습니다. 즉, 함수의 메모리 위치를 가리키는 특수 변수입니다. 그런 다음이를 사용하여 특정 인수로 기능을 호출 할 수 있습니다. 따라서 콜백 함수를 설정하는 함수가있을 것입니다. 이것은 기능 포인터를 허용 한 다음 사용할 수있는 곳에 주소를 저장합니다. 그 후 지정된 이벤트가 트리거되면 해당 기능을 호출합니다.

예를 통해 아이디어를 이해하는 것이 훨씬 쉽습니다. 지금까지 C의 콜백 함수에 대해 들었던 것은 훌륭한 답변이지만,이 기능을 사용하면 가장 큰 이점은 코드를 깨끗하고 깔끔하게 유지하는 것입니다.

예시

다음 C 코드는 빠른 정렬을 구현합니다. 아래 코드에서 가장 흥미로운 줄은 콜백 함수가 작동하는 것을 볼 수 있습니다.

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

compare_s2b는 qsort ()가 함수를 호출하는 데 사용하는 함수 이름입니다. 이렇게하면 QSORT ()가 너무 깔끔하게 유지됩니다 (따라서 유지하기가 더 쉽습니다). 다른 함수 내부에서 이름으로 함수를 호출합니다 (물론 기능 프로토 타입 선언은 다른 기능에서 호출되기 전에 미리 사전에 있어야합니다).

완전한 코드

#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);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top