1. What is a callback function?

Callback functions sound more impressive than ordinary functions just by their name. So what exactly is a callback function? Forgive me for not having read many books; I haven't seen a definition of callback functions in any book. I searched on Baidu and found a wide variety of opinions. A large portion use a scenario like this to explain: Person A goes to Person B's store to buy something, but it happens to be out of stock. Person A leaves their number with Person B, and Person B notifies Person A when it's in stock. This makes people think more of asynchronous operations rather than callbacks. There are also two English phrases that left a deep impression on me: 1) If you call me, I will call you back; 2) Don't call me, I will call you. They seem to make sense, but after careful thought, can't ordinary functions also accomplish these two points? So I think these statements are not quite appropriate, because they don't express the characteristics of callback functions, that is, they don't show the difference between them and ordinary functions. However, I think Baidu Baike's explanation is fairly good (although I often complain about Baidu Search...): A callback function is a function called through a function pointer. If you pass a function's pointer (address) as a parameter to another function, and when this pointer is used to call the function it points to, we say this is a callback function.

Let me first share my views. We can break down the term literally. For "callback function" (callback function), in Chinese it can actually be understood in two ways: 1) the function that is called back; 2) the function that turns around to perform the calling action. So what the heck is this "turning around to call"?

First, let's look at Wikipedia's analysis of callbacks:In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback. In other words, passing executable code to other code like a parameter, and this code will be called and executed at some point, this is called a callback. If the code is executed immediately, it's called a synchronous callback; if it's executed at a later time, it's called an asynchronous callback. We won't discuss synchronous and asynchronous here; please refer to relevant materials.

Now let's look at a concise and clear statement from an expert on Stack Overflow:A "callback" is any function that is called by another function which takes the first function as a parameter. In other words, when function F1 calls function F2, function F1 passes the pointer of another function F3 to function F2 as a parameter. During the execution of function F2, function F2 calls function F3. This action is called a callback, and the function F3 that was first passed in as a pointer and later called back is the callback function. By now you should understand the definition of a callback function, right?

2. Why use callback functions?

Many friends might wonder, why not just write the function name directly at the callback location like ordinary function calls? Wouldn't that work too? Why must we use callback functions? It's good to have this thought, because many examples explaining callback functions found online can actually be implemented entirely with ordinary function calls. To answer this question, let's first understand the benefits and purpose of callback functions, and that is decoupling. Yes, it's that simple an answer. It is precisely because of this characteristic that ordinary functions cannot replace callback functions. So, in my eyes, this is the biggest feature of callback functions. Let's look at an image on Wikipedia that I think is drawn very well.

Below is an incomplete piece of C code to illustrate the meaning of the above diagram:

Example

#include<stdio.h>
#include<softwareLib.h> // Include the header file of the Software library where the Library Function resides

int Callback() // Callback Function
{
    // TODO
    return 0;
}
int main() // Main program
{
    // TODO
    Library(Callback);
    // TODO
    return 0;
}

At first glance, a callback seems to be just a call between functions, no different from ordinary function calls. But on closer inspection, a key difference can be found: in a callback, the main program passes the callback function into the library function like a parameter. In this way, as long as we change the parameters passed into the library function, we can implement different functionality. Doesn't that feel very flexible? And there's no need to modify the library function's implementation at all. This is decoupling. Look more carefully: the main function and the callback function are on the same layer, while the library function is on another layer. Think about it: if the library function is not visible to us, we can't modify the library function's implementation, which means we can't make the library function call ordinary functions by modifying the library function. Then we can only achieve this by passing in different callback functions. This is also a common situation in daily work. Now, if we map main(), Library(), and Callback() back to the earlier F1, F2, and F3 functions, isn't it clearer?

Now that you understand the characteristics of callback functions, can you roughly figure out when they should be used? That's right, you can use callback functions in many places to replace ordinary function calls, but in my opinion, callback functions should be used when you need to reduce coupling.

3. How to use callback functions?

Now that you know what a callback function is and understand its characteristics, how should you use callback functions? Let's look at a simple, executable synchronous callback function code below.

Example

#include<stdio.h>

int Callback_1() // Callback Function 1
{
    printf("Hello, this is Callback_1 ");
    return 0;
}

int Callback_2() // Callback Function 2
{
    printf("Hello, this is Callback_2 ");
    return 0;
}

int Callback_3() // Callback Function 3
{
    printf("Hello, this is Callback_3 ");
    return 0;
}

int Handle(int (*Callback)())
{
    printf("Entering Handle Function. ");
    Callback();
    printf("Leaving Handle Function. ");
}

int main()
{
    printf("Entering Main Function. ");
    Handle(Callback_1);
    Handle(Callback_2);
    Handle(Callback_3);
    printf("Leaving Main Function. ");
    return 0;
}

Output:

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3
Leaving Handle Function.
Leaving Main Function.

As you can see, the parameter in the Handle() function is a pointer. When calling the Handle() function in the main() function, the function names Callback_1()/Callback_2()/Callback_3() are passed to it. At this point, the function name is the pointer to the corresponding function. In other words, a callback function is actually a usage of function pointers. Now read this sentence again: A "callback" is any function that is called by another function which takes the first function as a parameter. Isn't it clearer now?

4. How to use callback functions with parameters?

Sharp-eyed friends may have noticed that the callback functions in the previous examples have no parameters. So can we call back functions that have parameters? The answer is yes. Then how do we call them? We can simply modify the above example a bit:

Example

#include<stdio.h>

int Callback_1(int x) // Callback Function 1
{
    printf("Hello, this is Callback_1: x = %d ", x);
    return 0;
}

int Callback_2(int x) // Callback Function 2
{
    printf("Hello, this is Callback_2: x = %d ", x);
    return 0;
}

int Callback_3(int x) // Callback Function 3
{
    printf("Hello, this is Callback_3: x = %d ", x);
    return 0;
}

int Handle(int y, int (*Callback)(int))
{
    printf("Entering Handle Function. ");
    Callback(y);
    printf("Leaving Handle Function. ");
}

int main()
{
    int a = 2;
    int b = 4;
    int c = 6;
    printf("Entering Main Function. ");
    Handle(a, Callback_1);
    Handle(b, Callback_2);
    Handle(c, Callback_3);
    printf("Leaving Main Function. ");
    return 0;
}

Output:

Entering Main Function.
Entering Handle Function.
Hello, this is Callback_1: x = 2
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_2: x = 4
Leaving Handle Function.
Entering Handle Function.
Hello, this is Callback_3: x = 6
Leaving Handle Function.
Leaving Main Function.

As you can see, it's not as simple as directly changing int Handle(int (*Callback)()) to int Handle(int (*Callback)(int)). Instead, you need to add an additional parameter to store the callback function's parameter value, like the parameter y in int Handle(int y, int (*Callback)(int)) here. Similarly, callback functions with multiple parameters can be used.

Original article URL: https://www.cnblogs.com/jiangzhaowei/p/9129105.html