The callback function used to be so easy to understand

 

1 what is a callback function?

First, what is "callback"?

My understanding is: pass an executable code to other code like parameter passing, and this code will be called and executed at some time, which is called callback.

If the code is executed immediately, it is called synchronous callback. If it is executed later, it is called asynchronous callback.

A callback function is a function called through a function pointer. If you pass the pointer (address) of a function as a parameter to another function, when the pointer is used to call the function it points to, we say it is a callback function.

The callback function is not called directly by the implementer of the function, but by another party when a specific event or condition occurs, which is used to respond to the event or condition.

2 why use callback function?

Because the caller and the callee can be separated, the caller does not care who is the callee. It only needs to know that there is a called function with specific prototypes and constraints.

In short, the callback function allows the user to pass the pointer of the method to be called as a parameter to a function, so that the function can flexibly use different methods when dealing with similar events.

 

int Callback()    ///< callback function
{
    // TODO
    return 0;
}
int main()     ///< main function
{
    // TODO
    Library(Callback);  ///< library function callback through function pointer
    // TODO
    return 0;
}

Callbacks seem to be just calls between functions, no different from ordinary function calls.

But look carefully, you can find a key difference between the two: in the callback, the main program passes the callback function to the storage function like a parameter.

In this way, as long as we change the parameters passed into the library function, we can realize different functions. Do you think it is very flexible? And when the library function is very complex or invisible, the use of callback function is very excellent.

3 how to use callback function?

int Callback_1(int a)   ///< callback function 1
{
    printf("Hello, this is Callback_1: a = %d ", a);
    return 0;
}

int Callback_2(int b)  ///< callback function 2
{
    printf("Hello, this is Callback_2: b = %d ", b);
    return 0;
}

int Callback_3(int c)   ///< callback function 3
{
    printf("Hello, this is Callback_3: c = %d ", c);
    return 0;
}

int Handle(int x, int (*Callback)(int)) ///< note the function pointer definition used here
{
    Callback(x);
}

int main()
{
    Handle(4, Callback_1);
    Handle(5, Callback_2);
    Handle(6, Callback_3);
    return 0;
}

As shown in the above code: it can be seen that the parameter in the Handle() function is a pointer. When calling the Handle() function in the main() function, the function callback is passed in to it_ 1()/Callback_ 2()/Callback_ 3 (), the function name at this time is the pointer of the corresponding function, that is, the callback function is actually a use of function pointer.

4 callback function instance (very useful)

A small project of GPRS module networking. The students who have used it probably know that 2G, 4G, NB and other modules need to go through the steps of module power on initialization, network registration, network information quality query, server connection and so on in order to realize the wireless networking function. Here is an example of using a state machine function (calling the functions of different implementation methods according to different states in turn), Call different functions in turn through callback function to realize module networking function, as follows:

/*********  Working state processing*********/
typedef struct
{
 uint8_t mStatus;
 uint8_t (* Funtion)(void); //Form of function pointer
} M26_WorkStatus_TypeDef;  //The working state set of M26 calls the function


/**********************************************
** >M26 Working state set function
***********************************************/
M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
{    
    {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //Module shutdown
    {GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //Module startup
    {GPRS_NETWORK_Start,   M26_Work_Init  }, //Pin initialization
    {GPRS_NETWORK_CONF,  M26_NET_Config  }, /AT Instruction configuration
    {GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //Connect to dispatching center
    {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //Waiting for the reply from the dispatching center
    {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //Connect front-end processor
    {GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //Wait for the front-end processor to reply
    {GPRS_NETWORK_COMM,  M26_COMM   }, //Normal operation
    {GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //Waiting for signal reply
    {GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //Get signal value
    {GPRS_NETWORK_RESTART,  M26_RESET   }, //Module restart
}/**********************************************
** >M26 The module working state machine calls 12 functions in turn
***********************************************/
uint8_t M26_WorkStatus_Call(uint8_t Start)
{
    uint8_t i = 0;
    for(i = 0; i < 12; i++)
    {
        if(Start == M26_WorkStatus_Tab[i].mStatus)
        {          
      return M26_WorkStatus_Tab[i].Funtion();
        }
    }
    return 0;
}

Therefore, if someone wants to do an NB module networking project, they can copy the above framework. They only need to modify the specific implementation of the callback function, or add or reduce the callback function, so that the module networking can be realized concisely and quickly.

A treasure resource found recently can be shared with you. Click to get it

Keywords: C C++ Programming Interview

Added by Genux on Fri, 18 Feb 2022 22:24:55 +0200