回调函数案例(二)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 /****************************************
 5  * 函数指针结构体
 6  ***************************************/
 7 typedef struct _OP
 8 {
 9     float (*p_add)(float, float);
10     float (*p_sub)(float, float);
11     float (*p_mul)(float, float);
12     float (*p_div)(float, float);
13 } OP;
14 
15 /****************************************
16  * 加减乘除函数
17  ***************************************/
18 float ADD(float a, float b)
19 {
20     return a + b;
21 }
22 
23 float SUB(float a, float b)
24 {
25     return a - b;
26 }
27 
28 float MUL(float a, float b)
29 {
30     return a * b;
31 }
32 
33 float DIV(float a, float b)
34 {
35     return a / b;
36 }
37 
38 /****************************************
39  * 初始化函数指针
40  ***************************************/
41 void init_op(OP *op)
42 {
43     op->p_add = ADD;
44     op->p_sub = SUB;
45     op->p_mul = &MUL;
46     op->p_div = &DIV;
47 }
48 
49 /****************************************
50  * 库函数
51  ***************************************/
52 float add_sub_mul_div(float a, float b, float (*op_func)(float, float))
53 {
54     return (*op_func)(a, b);
55 }
56 
57 int main(int argc, char *argv[])
58 {
59     OP *op = (OP *)malloc(sizeof(OP));
60     init_op(op);
61 
62     /* 直接使用函数指针调用函数 */
63     printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n", (op->p_add)(1.3, 2.2), (*op->p_sub)(1.3, 2.2),
64            (op->p_mul)(1.3, 2.2), (*op->p_div)(1.3, 2.2));
65 
66     /* 调用回调函数 */
67     printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n",
68            add_sub_mul_div(1.3, 2.2, ADD),
69            add_sub_mul_div(1.3, 2.2, SUB),
70            add_sub_mul_div(1.3, 2.2, MUL),
71            add_sub_mul_div(1.3, 2.2, DIV));
72            
73     free(op);
74 
75     return 0;
76 }

 百度百科:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

 

wiki百科:

      有两种类型的回调,它们在运行时控制数据流的方式不同:阻塞回调(也称为同步回调或仅回调)和延迟回调(也称为异步回调)。虽然在函数返回之前调用阻塞回调(在下面的C示例中,它说明了阻塞回调,它是函数main),但是在函数返回后可以调用延迟回调。延迟回调通常在I / O操作或事件处理的上下文中使用,并且在多个线程的情况下由中断或不同的线程调用。由于它们的性质,阻塞回调可以在没有中断或多线程的情况下工作,这意味着阻塞回调通常不用于同步或将工作委托给另一个线程。
      回调用于对窗口系统中的应用程序进行编程。在这种情况下,应用程序提供(引用)特定的自定义回调函数,供操作系统调用,然后调用此特定于应用程序的函数以响应鼠标单击或按键等事件。这里的一个主要问题是权限和安全性的管理:虽然从操作系统调用该函数,但它不应该以与系统相同的权限运行。该问题的解决方案是使用保护环。

 

回调的形式因编程语言而异:在汇编语言,C语言,C ++,Pascal,Modula2和类似语言中,函数的机器级指针可作为参数传递给另一个(内部或外部)函数。这得到了大多数编译器的支持,并且提供了在不使用特殊包装器库或类的情况下一起使用不同语言的优势。一个示例可以是直接(或多或少)可由许多不同语言,编译器和汇编器访问的Windows API。

C语言中的回调函数:

回调具有广泛的用途,例如在错误信令中:Unix程序可能不希望在收到SIGTERM时立即终止,因此为了确保正确处理其终止,它会将清理函数注册为回调。回调也可用于控制函数是否起作用:Xlib允许指定自定义谓词以确定程序是否希望处理事件。
以下C代码演示了使用回调来显示两个数字。

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

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

/* 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;
}

运行结果:

125185 and 89187225
 9084 and 9441
 42 and 42

请注意,这与简单地将回调函数的输出传递给调用函数PrintTwoNumbers()有所不同 - 而不是两次打印相同的值,PrintTwoNumbers会根据需要多次调用回调。这是回调的两个主要优点之一。
另一个优点是调用函数可以将它希望的任何参数传递给被调用的函数(在上面的例子中没有显示)。这允许正确的信息隐藏:将回调传递给调用函数的代码不需要知道将传递给函数的参数值。如果它只传递了返回值,则需要公开公开参数。另一个例子:

这是一个简单的C程序,用于演示回调的用法*回调函数与调用代码位于同一文件中。
 *回调函数以后可以放入外部库,例如*共享对象以增加灵活性

/*
 * This is a simple C program to demonstrate the usage of callbacks
 * The callback function is in the same file as the calling code.
 * The callback function can later be put into external library like
 * e.g. a shared object to increase flexibility.
 *
 */

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

typedef struct _MyMsg
{
    int appId;
    char msgbody[32];
} MyMsg;

void myfunc(MyMsg *msg)
{
    if (strlen(msg->msgbody) > 0 )
        printf("App Id = %d \nMsg = %s \n",msg->appId, msg->msgbody);
    else
        printf("App Id = %d \nMsg = No Msg\n",msg->appId);
}

/*
 * Prototype declaration
 */
void (*callback)(MyMsg *);

int main(void)
{
    MyMsg msg1;
    msg1.appId = 100;
    strcpy(msg1.msgbody, "This is a test\n");

    /*
     * Assign the address of the function "myfunc" to the function
     * pointer "callback" (may be also written as "callback = &myfunc;")
     */
    callback = myfunc;

    /*
     * Call the function (may be also written as "(*callback)(&msg1);")
     */
    callback(&msg1);

    return 0;
}

运行结果:

App Id = 100
Msg = This is a test

此信息隐藏意味着可以在进程或线程之间进行通信时使用回调,也可以通过序列化通信和表格数据进行回调。
posted @ 2019-04-13 09:27  wdliming  阅读(712)  评论(0编辑  收藏  举报