[Registro diario] Función puntero y función de devolución de llamada

 

1. Puntero de función y su definición y uso 

1. ¿Qué es un puntero de función?

2. Cómo llamar a una función con un puntero de función

Dos, función de devolución de llamada (devolución de llamada)

1. ¿Qué es una función de devolución de llamada?

2. ¿Por qué utilizar la función de devolución de llamada?

3. ¿Cómo utilizar la función de devolución de llamada?

4. ¿Cómo utilizar la función de devolución de llamada con parámetros?

 


1. Puntero de función y su definición y uso 

Enlace de referencia: puntero de función y su definición y uso, explicación detallada del puntero de función en lenguaje C

1. ¿Qué es un puntero de función?

Si se define una función en el programa, el sistema asignará una sección de espacio de almacenamiento para el código de función en el momento de la compilación.La primera dirección de esta sección de espacio de almacenamiento se denomina dirección de la función. Y el nombre de la función representa esta dirección. Dado que es una dirección, podemos definir una variable de puntero para almacenarla. Esta variable de puntero se llama una variable de puntero de función , o puntero de función para abreviar .

Entonces, ¿cómo definir esta variable de puntero de función? Aunque también apunta a una dirección, la variable de puntero que apunta a la función se define de manera diferente a la variable de puntero que apunta a la variable que mencionamos anteriormente. P.ej:

指向变量的指针变量:int (*p);

指向函数的指针变量:int (*p)(int, int);

Esta declaración define una variable puntero p que apunta a la función. Primero, es una variable de puntero, por lo que debe haber un "*", es decir (* p); en segundo lugar, el int en el frente indica que la variable de puntero puede apuntar a una función cuyo tipo de valor de retorno es int; los dos ints en el corchete posterior indican el puntero Las variables pueden apuntar a funciones que tienen dos parámetros y ambos son de tipo int. Entonces, el significado combinado de esta declaración es: se define una variable de puntero p, que puede apuntar a una función cuyo tipo de valor de retorno es tipo int y tiene dos parámetros enteros. El tipo de p es int (*) (int, int).

Entonces, la definición de puntero de función es:

Tipo de valor de retorno de función (* nombre de variable de puntero) (lista de parámetros de función);

 "Tipo de valor de retorno de función" indica que la variable de puntero puede apuntar a una función con qué tipo de valor de retorno; "lista de parámetros de función" indica que la variable de puntero puede apuntar a una función con qué lista de parámetros. Esta lista de parámetros solo necesita escribir el tipo de parámetro de la función .

Pequeño consejo: la definición de puntero de función es cambiar el "nombre de función" en la "declaración de función" a "(* nombre de variable de puntero)". ejemplo:

函数是:  int max(int a,int b);

函数指针:int (*p)(int,int);

Nota:

1. Los paréntesis en ambos extremos de "(* nombre de variable de puntero)" no se pueden omitir. Los paréntesis cambian la prioridad de los operadores. Si se omiten los paréntesis, no es un puntero de función sino una declaración de función, es decir, se declara una función cuyo tipo de valor de retorno es un tipo de puntero.

2. La diferencia entre un puntero a función y un puntero a una variable es que hay paréntesis con tipos de parámetros formales detrás del nombre de variable del puntero a función.

3. El puntero de función no tiene operaciones ++ y -.

2. Cómo llamar a una función con un puntero de función

Para la función max (int, int), los valores de max y & max son los mismos. Entonces, agregar o no agregar & es lo mismo.

#include <stdio.h>
 
int max(int x, int y)
{
    return x > y ? x : y;
}
 
int main(void)
{
    /* p 是函数指针 */
    int (* p)(int, int) =  &max; // &可以省略
    int a, b, c, d;
 
    printf("请输入三个数字:");
    scanf("%d %d %d", & a, & b, & c);
 
    /* 与直接调用函数等价,d = max(max(a, b), c) */
    d = p(p(a, b), c); 
 
    printf("最大的数字是: %d\n", d);
 
    return 0;
}

Después de compilar y ejecutar, los resultados son los siguientes:

请输入三个数字:1 2 3
最大的数字是: 3

Dos, función de devolución de llamada (devolución de llamada)

Enlace de referencia: la función de devolución de llamada en lenguaje C explica la   comprensión popular de la "función de devolución de llamada"

1. ¿Qué es una función de devolución de llamada?

Echemos un vistazo a la definición en inglés de devolución de llamada:

Una devolución de llamada es una función que se pasa como argumento a otra función y se ejecuta después de que su función principal se haya completado。

Entendido literalmente, una función de devolución de llamada es un parámetro, y esta función se pasa como parámetro a otra función. Después de que se ejecuta esa función, se ejecuta la función pasada. En otras palabras, cuando la función F1 llama a la función F2, la función F1 pasa otro puntero de función F3 a la función F2 a través de parámetros. Durante la ejecución de la función F2, la función F2 llama a la función F3. Esta acción se llama callback (Callback ), y la función F3, que primero se pasa como puntero y luego se vuelve a llamar, es la función de devolución de llamada.

Dé un ejemplo que otros hayan dado:

Después de la cita, envías a tu novia a casa. Cuando te vayas, definitivamente dirás: "Envíame un mensaje cuando llegues a casa. Estoy muy preocupado por ti". No, entonces tu novia realmente te envió un mensaje cuando llegó a casa. un mensaje. Chico, tienes un espectáculo. De hecho, este es un proceso de devolución de llamada. Dejas una función de parámetro (pedirle a tu novia que te envíe un mensaje) para tu novia, y luego tu novia se va a casa. La acción para ir a casa es la función principal. Primero debe regresar a casa después de que se ejecute la función principal, y luego ejecutar la función pasada, y luego recibirá un mensaje.

2. ¿Por qué utilizar la función de devolución de llamada?

Muchos amigos pueden pensar, ¿por qué no escribir el nombre de la función directamente en el lugar de devolución de llamada como una llamada de función normal? ¿No te parece bien? ¿Por qué tenemos que usar una función de devolución de llamada? Es bueno tener esta idea, porque vi muchos ejemplos de análisis de funciones de devolución de llamada en Internet, pero en realidad se pueden implementar con llamadas a funciones ordinarias. Para responder a esta pregunta, primero comprendamos los beneficios y las funciones de volver a las funciones, es decir, el desacoplamiento. Sí, es una respuesta tan simple. Debido a esta característica, las funciones ordinarias no pueden reemplazar las funciones de devolución de llamada. Por lo tanto, en mi opinión, esta es la característica más importante de la función de devolución de llamada. Eche un vistazo a una imagen en Wikipedia que creo que está bien dibujada.

Función de devolución de llamada en lenguaje C detallada

 El siguiente es un código de lenguaje C incompleto para mostrar el significado de la imagen de arriba:

#include<stdio.h>
#include<softwareLib.h> // 包含Library Function所在读得Software library库的头文件
 
int Callback() // Callback Function
{
    // TODO
    return 0;
}
 
int main() // Main program
{ 
    // TODO
    Library(Callback);
    // TODO
    return 0;
}

A primera vista, las devoluciones de llamada parecen ser solo llamadas entre funciones, que no son diferentes de las llamadas a funciones ordinarias, pero una mirada más cercana revela una diferencia clave entre las dos: en la devolución de llamada, el programa principal pasa la función de devolución de llamada como un parámetro Función entrante. De esta manera, siempre que cambiemos los parámetros pasados ​​a la función de la biblioteca, podemos lograr diferentes funciones ¿Se siente esto muy flexible? Y no hay necesidad de modificar la implementación de las funciones de la biblioteca en absoluto, lo que es un desacoplamiento. Eche un vistazo más de cerca. La función principal y la función de devolución de llamada están en la misma capa, mientras que la función de biblioteca está en otra capa. Piénselo. Si la función de biblioteca no está visible para nosotros, no podemos modificar la implementación de la función de biblioteca, lo que significa que no se puede modificar. La función de biblioteca permite que la función de biblioteca llame a la función ordinaria, por lo que solo podemos pasar diferentes funciones de devolución de llamada, lo cual es una situación común en el trabajo diario. Ahora vuelva a colocar las funciones main (), Library () y Callback () en las funciones anteriores F1, F2 y F3. ¿No está más claro?

Después de comprender las características de la función de devolución de llamada, ¿es posible saber aproximadamente en qué circunstancias se debe utilizar? Sí, puede usar funciones de devolución de llamada en muchos lugares para reemplazar las llamadas a funciones ordinarias, pero en mi opinión, si necesita reducir el acoplamiento, debe usar funciones de devolución de llamada.

3. ¿Cómo utilizar la función de devolución de llamada?

Sabiendo qué es una función de devolución de llamada y entendiendo las características de la función de devolución de llamada, ¿cómo debería usarse la función de devolución de llamada? Veamos un código de función de devolución de llamada síncrona simple que se puede ejecutar.

#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;

}
运行结果:

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.

Como puede ver, el parámetro en la función Handle () es un puntero. Cuando se llama a la función Handle () en la función main (), se le pasa el nombre de la función Callback_1 () / Callback_2 () / Callback_3 (). El nombre de la función en este momento es el puntero a la función correspondiente, es decir, la función de devolución de llamada es en realidad un uso del puntero de función. Ahora lea esta oración nuevamente: Una "devolución de llamada" es cualquier función que es llamada por otra función que toma la primera función como parámetro, ¿está más claro?

4. ¿Cómo utilizar la función de devolución de llamada con parámetros?

Los amigos más perspicaces pueden haber descubierto que la función de devolución de llamada en el ejemplo anterior no tiene parámetros, entonces, ¿podemos llamar a esas funciones con parámetros? La respuesta es sí. Entonces, ¿cómo llamarlo? Podemos modificar ligeramente el ejemplo anterior:

#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;

}
运行结果:

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.

Como puede ver, no es suficiente cambiar directamente int Handle (int (* Callback) ()) a int Handle (int (* Callback) (int)), sino guardar los parámetros de la función de devolución de llamada agregando otro parámetro Valor, como el parámetro y de int Handle (int y, int (* Callback) (int)) aquí. Del mismo modo, puede utilizar una función de devolución de llamada con varios parámetros.

Supongo que te gusta

Origin blog.csdn.net/qq_27148893/article/details/109275852
Recomendado
Clasificación