DMarlon Studio

Lección 6 · 6 de 20

Punteros a funciones y callbacks · C

Guarde funciones en variables y arrays con punteros a funciones en C y páselas como callbacks: reglas de precios aplicadas por pasos.

C · Punteros a funciones y callbacks en DMarlon Studio: el código del ejemplo y su salida en la terminal

Una función también tiene una dirección, y un puntero a función la guarda. La sintaxis es enrevesada, así que se le pone nombre con typedef: typedef double (*PriceRule)(double); define PriceRule como «puntero a una función que recibe un double y devuelve un double». add_vat, discount y round_up encajan en ese tipo.

apply_all recibe una de esas funciones en el parámetro rule y la llama con rule(prices[i]) para cada precio. Es un callback: apply_all sabe recorrer el array, pero lo que se hace con cada precio lo decide quien la llama.

Al pasar una función basta su nombre, sin paréntesis: discount es la dirección de la función; discount(5) sería llamarla.

steps es un array de structs con un nombre y una regla. El bucle aplica las reglas en orden (descuento del 10 %, IVA del 21 % y redondeo hacia arriba) y escribe los precios después de cada paso. Cambiar el orden o añadir una regla es tocar solo la tabla, no el bucle.

Los punteros a funciones están por todas partes en C: qsort recibe la función que compara, atexit la que se ejecuta al salir y las bibliotecas de interfaz gráfica, la que responde a cada botón.

Código · main.c

#include <stdio.h>// A type for "a function that takes a double and returns a double".typedef double (*PriceRule)(double);double add_vat(double p)  { return p * 1.21; }double discount(double p) { return p * 0.90; }double round_up(double p) { return (int)(p + 0.99); }// apply_all receives a callback: what to do with each price is up to the caller.void apply_all(double *prices, int n, PriceRule rule) {    for (int i = 0; i < n; i++) prices[i] = rule(prices[i]);}void print_prices(const char *label, const double *prices, int n) {    printf("%-12s", label);    for (int i = 0; i < n; i++) printf(" %7.2f", prices[i]);    printf("\n");}int main(void) {    double prices[] = {10.00, 24.50, 7.95, 99.00};    int n = sizeof prices / sizeof prices[0];    print_prices("Start", prices, n);    // A table of named rules: an array of function pointers.    struct { const char *name; PriceRule rule; } steps[] = {        {"Discount", discount}, {"With VAT", add_vat}, {"Rounded", round_up},    };    for (int s = 0; s < 3; s++) {        apply_all(prices, n, steps[s].rule);        print_prices(steps[s].name, prices, n);    }    return 0;}

Salida · cc main.c -o main && ./main

Start          10.00   24.50    7.95   99.00
Discount        9.00   22.05    7.16   89.10
With VAT       10.89   26.68    8.66  107.81
Rounded        11.00   27.00    9.00  108.00

Para recordar

  • typedef R (*Nombre)(params); da nombre al tipo de puntero a función.
  • El nombre de la función sin () es su dirección.
  • Un callback es una función que se pasa a otra para que la llame.
  • Una tabla de structs con punteros a funciones sustituye a un switch largo.

Ejercicio

Añada la regla psychological, que deja cada precio en x,99 (por ejemplo, 27.00 pasa a 26.99), y póngala al final de la tabla steps.