¿Cuál es el concepto de funciones de devolución de llamada en C? ¿Por qué no se puede hacer simplemente invocando la función por su nombre en lugar de pasar la dirección de la función a la otra función y luego invocarla?

Las rellamadas tendrán mucho más sentido cuando esté escribiendo una API, por ejemplo. Supongamos que está escribiendo una biblioteca de funciones para que la use alguien más. Usted, en este punto, no debería estar agobiado con el lugar exacto en el que se va a usar su API. Debería centrarse en obtener las características correctas entre los puntos límite de sus funciones. Después de terminar el trabajo, puede devolver los resultados. Todo bien hasta ahora. Ahora, permítanos introducir una restricción de que sus funciones son asíncronas. Las personas que llaman pueden llamar a su función y esperar que los resultados sean devueltos en un momento futuro. Mientras tanto, las personas que llaman son libres de hacer lo que sea apropiado, en lugar de esperar mundanamente a que su API termine todo el trabajo. Esto es hermoso. Muy elegante. Ahora, todo lo que necesitamos es su API para saber qué hacer con los resultados cuando el trabajo esté terminado. Llega la importancia de las funciones de devolución de llamada. Las funciones de devolución de llamada son rutinas que acepta invocar en el futuro para comunicarse con las personas que llaman. La devolución de llamada se puede usar para devolver resultados, estados, errores o como mínimo para indicar que el trabajo está completo. Dado que como escritor de API no tiene idea de qué programas consumen sus funciones, no hay forma de que sepa a qué función debe devolver la llamada cuando los resultados estén disponibles. Por lo tanto, no puede codificar nombres de funciones.

Al igual que en el ejemplo anterior, es posible que desee mostrar el carácter ‘@’ y moverlos de manera diferente.

mediante el uso de devolución de llamada, esto se puede hacer fácilmente.

hacer estructura

struct Actor;
typedef void (* fptr) (struct Actor * a);
typedef struct Actor
{
int x, y;
fptr fn;
} Actor;

poblar actor con valor inicial.

Actores actores [3];
void move_rand (Actor *);
void move_right (Actor *);
void move_up (Actor *);
void main_loop ();
int main ()
{
actores [0] .x = 10; actores [0] .y = 10; actores [0] .fn = move_rand;
actores [1] .x = 10; actores [1] .y = 10; actores [1] .fn = move_right;
actores [2] .x = 10; actores [2] .y = 10; actores [2] .fn = move_up;
while (1) {main_loop ();}
}

y solo ejecuta cada fn de los actores. Por supuesto, puedes dibujar para ver si funciona.

el fn de cada actor modificará las x, y del actor de forma diferente porque fn contiene funciones diferentes.

#include // para la función Sleep ()
void draw ();
void main_loop ()
{
para (int i = 0; i <3; i ++)
{
Actor * a = & (actores [i]);
a-> fn (a);
}
dibujar();
Sueño (1000);
}

Aquí está move_rand, move_right, move_up example

void move_rand (Actor * a)
{
a-> x + = (rand ()% 3) -1;
a-> y + = (rand ()% 3) -1;
}
void move_up (Actor * a)
{
a-> y – = 1;
}
void move_right (Actor * a)
{
a-> x + = 1;
}

Para su curiosidad, he aquí cómo dibujar. (Pero esto no contiene doble buffering).

#include // para el sistema ()
#include
void gotoxy (int x, int y)
{
COORD p = {x, y};
HANDLE h = GetStdHandle (STD_OUTPUT_HANDLE);
SetConsoleCursorPosition (h, p);
}
void draw ()
{
sistema (“cls”);
para (int i = 0; i <3; i ++)
{
Actor * a = & (actores [i]);
int x = a-> x; int y = a-> y;
gotoxy (x, y);
printf (“@”);
}
}