Puntero de función en C

Jinku Hu 12 octubre 2023
  1. Utilizar la notación void (*func)() para definir un puntero de función en C
  2. Utilizar el array de punteros de función para implementar la característica de programación genérica de tipos
Puntero de función en C

Este artículo presentará cómo utilizar un puntero de función en C.

Utilizar la notación void (*func)() para definir un puntero de función en C

Los punteros de función son otra construcción en la programación en C que implementa características avanzadas como la llamada a funciones dinámicas, estructuras que incluyen sus propios métodos similares al diseño orientado a objetos, programación de tipo genérico, etc. Tenga en cuenta que la declaración de punteros a funciones puede tener una sintaxis complicada, en concreto, la notación void (*func)(void) declara el puntero a una función void que no toma parámetros. Aunque asignamos la dirección de la función printInt, que toma un solo argumento int al puntero de función de tipo void (*func)(void) en el siguiente ejemplo. Una vez definido el puntero de función llamado func, puede ser llamado con la notación habitual de llamada a función func(arg) o con el operador de desreferenciación (*func)(arg).

#include <stdio.h>
#include <stdlib.h>

void printInt(int x) { printf("printed from printInt: %d\n", x); }

int main() {
  int input1 = 10233;

  void (*func)(int) = printInt;

  func(input1);
  (*func)(input1);

  exit(EXIT_SUCCESS);
}

Producción :

printed from printInt: 10233
printed from printDouble: 11.234000

Alternativamente, podemos definir un nuevo alias de tipo de un puntero de función usando typedef para hacer el código más legible. Tenga en cuenta que diferentes tipos de funciones necesitarían declaraciones typedef separadas. En el siguiente ejemplo de código, definimos un puntero a una función void sin argumentos; no obstante, las direcciones de las funciones printInt y printDouble se almacenan en la variable de tipo FuncPtr. Cabe destacar que la dirección de la función específica puede tomarse con el operador explícito & o con la asignación implícita del propio nombre de la función, como se demuestra en el siguiente ejemplo.

#include <stdio.h>
#include <stdlib.h>

typedef void (*FuncPtr)();

void printInt(int x) { printf("printed from printInt: %d\n", x); }

void printDouble(double x) { printf("printed from printDouble: %f\n", x); }

int main() {
  int input1 = 10233;
  double input2 = 11.234;

  FuncPtr func1 = printInt;
  FuncPtr func2 = printDouble;

  func1(input1);
  func2(input2);

  exit(EXIT_SUCCESS);
}

Producción :

printed from printInt: 10233
printed from printDouble: 11.234000

Utilizar el array de punteros de función para implementar la característica de programación genérica de tipos

Al igual que otros objetos, uno puede definir un array de punteros a funciones con la notación entre paréntesis []. Este array puede ser utilizado para elegir y llamar a funciones específicas durante el tiempo de ejecución fácilmente. Obsérvese que estamos utilizando la palabra clave _Generic, que es un switch como una expresión que permite al usuario elegir el caso específico basado en la evaluación del tipo de la expresión controladora. En consecuencia, implementamos el siguiente ejemplo de código, donde la función print correspondiente es llamada en base al tipo de la variable pasada en la condición switch. Nótese que el tipo enum también se utiliza para definir valores constantes para diferentes casos.

#include <stdio.h>
#include <stdlib.h>

enum TYPE { INTEGER, DOUBLE, INVALID };

#define typename(x) \
  _Generic((x), int: INTEGER, double: DOUBLE, default: INVALID)

typedef void (*FuncPtr)();

void printInt(int x) { printf("printed from printInt: %d\n", x); }

void printDouble(double x) { printf("printed from printDouble: %f\n", x); }

int main() {
  int input1 = 10233;
  double input2 = 11.234;

  FuncPtr func_ptrs[] = {printInt, printDouble};

  switch (typename(input1)) {
    case INTEGER:
      func_ptrs[INTEGER](input1);
      break;
    case DOUBLE:
      func_ptrs[DOUBLE](input1);
      break;
    case INVALID:
      printf("No corresponding type found!\n");
    default:
      break;
  }

  switch (typename(input2)) {
    case INTEGER:
      func_ptrs[INTEGER](input2);
      break;
    case DOUBLE:
      func_ptrs[DOUBLE](input2);
      break;
    case INVALID:
      printf("No corresponding type found!\n");
    default:
      break;
  }

  exit(EXIT_SUCCESS);
}

Producción :

printed from printInt: 10233
printed from printDouble: 11.234000
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artículo relacionado - C Pointer