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);
C语言中的回调函数等同于被分配给另一个函数使用的函数参数/变量。Wiki Example 在下面的代码中,
#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;
}
C语言中的回调函数是一个提供给另一个函数的函数,当另一个函数正在执行其任务时,它可以在某个时间点“回调到”。 有two ways that a callback is used:同步回调和异步回调。同步回调提供给另一个函数,该函数将执行某个任务,然后将完成的任务返回给调用者。异步回调提供给另一个函数,该函数将启动一个任务,然后将可能未完成的任务返回给调用者。
#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实用程序或Web浏览器尝试在另一个窗口中连接来进行练习。 我从Microsoft提供的accept()函数https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx示例中提取了大部分WinSock代码 此应用程序使用端口8282在本地主机www.example.com上启动listen()127.0.0.1,因此您可以使用telnet 127.0.0.1 8282或http://127.0.0.1:8282/。 此示例应用程序是使用Visual Studio 2017社区版创建的控制台应用程序,它使用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);
}
#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);
}
9条答案
按热度按时间oknwwptz1#
在C语言中没有“回调”--没有比任何其他通用编程概念更多的东西。
它们是用函数指针实现的。下面是一个例子:
这里,
populate_array
函数将函数指针作为其第三个参数,并调用它来获取要填充数组的值。我们已经编写了回调函数getNextRandomValue
,它返回一个random-ish值,并将指向它的指针传递给populate_array
。populate_array
将调用回调函数10次,并将返回的值赋给给定数组中的元素。luaexgnf2#
下面是C语言中回调的一个例子。
假设您要编写一些代码,允许在发生某个事件时调用注册回调。
首先定义用于回调的函数类型:
现在,定义一个用于注册回调的函数:
下面是注册回调的代码:
在事件分派程序的内部,回调可能存储在如下所示的结构中:
这是执行回调的代码。
bis0qfac3#
一个简单的回叫程序。希望它能回答你的问题。
kq4fsx7k4#
C语言中的回调函数等同于被分配给另一个函数使用的函数参数/变量。Wiki Example
在下面的代码中,
函数调用PrintTwoNumbers中的函数(*numberSource)是一个函数,用于在运行时根据代码指示从PrintTwoNumbers内部“回调”/执行。
因此,如果你有一个pthread函数,你可以从它的示例化中分配另一个函数在循环内运行。
bnl4lu3b5#
C语言中的回调函数是一个提供给另一个函数的函数,当另一个函数正在执行其任务时,它可以在某个时间点“回调到”。
有two ways that a callback is used:同步回调和异步回调。同步回调提供给另一个函数,该函数将执行某个任务,然后将完成的任务返回给调用者。异步回调提供给另一个函数,该函数将启动一个任务,然后将可能未完成的任务返回给调用者。
同步回调
同步回调通常用于提供对另一个函数的委托,另一个函数将任务的某个步骤委托给该委托。这种委托的典型示例是来自C标准库的函数
bsearch()
和qsort()
。这两个函数都接受回调,该回调在函数提供的任务期间使用,以便搜索的数据类型在bsearch()
的情况下,或者在qsort()
的情况下,sorted不需要被所使用的函数所知道。例如,下面是一个小的示例程序,其中
bsearch()
使用了不同的比较函数,演示了同步回调。通过允许我们将数据比较委托给回调函数,bsearch()
函数允许我们在运行时决定要使用哪种比较。这是同步的,因为当bsearch()
函数返回时,任务就完成了。异步回调
异步回调的不同之处在于,当我们提供回调的被调用函数返回时,任务可能无法完成。这种类型的回调通常用于异步I/O,在这种情况下,I/O操作开始,然后当它完成时,调用回调。
在下面的程序中,我们创建了一个套接字来监听TCP连接请求,当收到请求时,监听的函数调用提供的回调函数。这个简单的应用程序可以通过在一个窗口中运行它,同时使用
telnet
实用程序或Web浏览器尝试在另一个窗口中连接来进行练习。我从Microsoft提供的
accept()
函数https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx示例中提取了大部分WinSock代码此应用程序使用端口8282在本地主机www.example.com上启动
listen()
127.0.0.1,因此您可以使用telnet 127.0.0.1 8282
或http://127.0.0.1:8282/
。此示例应用程序是使用Visual Studio 2017社区版创建的控制台应用程序,它使用Microsoft WinSock版本的套接字。对于Linux应用程序,WinSock函数需要替换为Linux替代项,Windows线程库将使用
pthreads
。u7up0aaq6#
C语言中的回调通常使用函数指针和相关的数据指针来实现。例如,您将函数
on_event()
和数据指针传递给框架函数watch_events()
。当事件发生时,您的函数将被调用,其中包含您的数据和一些特定于事件的数据。回调也用于GUI编程。GTK+ tutorial在theory of signals and callbacks上有一个很好的部分。
nfs0ujit7#
这个wikipedia article有一个C语言的例子。
一个很好的例子是,为增强Apache Web服务器而编写的新模块向主apache进程注册,方法是向它们传递函数指针,以便回调这些函数来处理网页请求。
eaf3rand8#
通过例子来理解一个想法要容易得多。到目前为止,关于C中的回调函数所讲的都是很好的答案,但使用该特性的最大好处可能是保持代码干净整洁。
示例
下面的C代码实现了快速排序。下面的代码中最有趣的一行是这一行,我们可以看到回调函数的作用:
compare_s2b是qsort()用来调用函数的函数名。这使qsort()保持整洁(因此更容易维护)。您只需在另一个函数中通过名称调用一个函数(当然,函数原型声明至少必须在从另一个函数调用它之前进行)。
完整的代码
ie3xauqp9#
通常这可以通过使用函数指针来完成,函数指针是一个指向函数内存位置的特殊变量。然后你可以用它来调用具有特定参数的函数。因此,可能会有一个设置回调函数的函数。它会接受一个函数指针,然后将该地址存储在可以使用的地方。之后,当指定的事件被触发时,它将调用该函数。