C에서 '콜백'이란 무엇이며 어떻게 구현됩니까?
제가 읽어본 바로는 코어 오디오는 콜백에 크게 의존하고 있습니다(및 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의 콜백은 다른 함수가 작업을 수행할 때 어느 시점에서 "콜백"하기 위해 다른 함수에 제공되는 함수입니다.
콜백을 사용하는 방법에는 동기 콜백과 비동기 콜백의 두 가지가 있습니다.동기 콜백은, 몇개의 태스크를 실행해, 완료하고 나서 발신자에게 돌아옵니다.비동기 콜백은 작업을 시작하여 작업이 완료되지 않은 상태로 발신자에게 반환되는 다른 함수에 제공됩니다.
동기 콜백은 일반적으로 다른 함수가 작업의 일부 단계를 위임하는 다른 함수에 위임자를 제공하기 위해 사용됩니다. 바로 이 위임의 함수'입니다.bsearch()
★★★★★★★★★★★★★★★★★」qsort()
C c 、 C 、 C c c 、 C 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 접속 요구를 리슨 하는 소켓을 작성해, 요구를 수신하면, 리슨 하는 함수가 제공된 콜백 함수를 기동합니다.은 1개의 수, 1번 창으로 할 수 .telnet
유틸리티 또는 웹 브라우저를 사용하여 다른 창에서 연결을 시도합니다.
의 을, 의 「WinSock」의했습니다.accept()
https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx에서 기능하다
은 " " " 를 합니다.listen()
.1에서는, 「127.0.0.1」의 어느쪽인가를 할 수 .telnet 127.0.0.1 8282
★★★★★★★★★★★★★★★★★」http://127.0.0.1:8282/
.
Visual Studio 2017 Community Edition Microsoft WinSock 버버 win 。를 Linux 스레드 를 사용합니다.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);
}
C의 콜백 함수는 다른 함수 내에서 사용하도록 할당된 함수 파라미터/변수와 동일합니다.Wiki의 예
아래 코드에서는
#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;
}
함수(*number)소스)는 PrintTwoNumbers라는 함수의 내부에 있으며 실행 시 코드에 의해 지시된 대로 PrintTwoNumbers 내부에서 "콜백"/실행하는 함수입니다.
따라서 pthread 함수 같은 것이 있으면 인스턴스화에서 루프 내에서 실행할 다른 함수를 할당할 수 있습니다.
이 위키피디아 글은 C에 예가 있습니다.
좋은 예로는 Apache Web 서버를 증강하기 위해 작성된 새로운 모듈이 함수 포인터를 전달함으로써 메인 아파치 프로세스에 등록되므로 이러한 함수는 웹 페이지 요청을 처리하기 위해 호출됩니다.
C의 콜백은 보통 함수 포인터와 관련된 데이터 포인터를 사용하여 구현됩니다.입니다.on_event()
함수에 포인터.watch_events()
(일부러)이벤트가 발생하면 데이터 및 일부 이벤트별 데이터와 함께 함수가 호출됩니다.
콜백은 GUI 프로그래밍에서도 사용됩니다.GTK+ 튜토리얼에는 신호와 콜백 이론에 대한 좋은 섹션이 있습니다.
일반적으로 이것은 함수의 메모리 위치를 가리키는 특수 변수인 함수 포인터를 사용하여 수행할 수 있습니다.그런 다음 이를 사용하여 특정 인수를 사용하여 함수를 호출할 수 있습니다.따라서 콜백 함수를 설정하는 함수가 있을 수 있습니다.그러면 함수 포인터가 받아들여지고 사용할 수 있는 곳에 주소가 저장됩니다.그 후 지정된 이벤트가 트리거되면 해당 함수를 호출합니다.
언급URL : https://stackoverflow.com/questions/142789/what-is-a-callback-in-c-and-how-are-they-implemented
'programing' 카테고리의 다른 글
평면에 점을 3D로 투영하려면 어떻게 해야 합니까? (0) | 2022.07.10 |
---|---|
NuxtJS/VueJs: 페이지가 클라이언트 측에서만 렌더링되었는지 확인하는 방법 (0) | 2022.07.10 |
효율성: 어레이와 포인터 비교 (0) | 2022.07.10 |
vuejs2 데이터에 하위 구성 요소 동적 삽입($compile 또는 v-html 남용 없음) (0) | 2022.07.10 |
Unsupported Operation이 표시되는 이유목록에서 요소를 제거하려고 할 때 예외가 발생합니까? (0) | 2022.07.10 |