Pointeur de fonction en C

Jinku Hu 12 octobre 2023
  1. Utiliser la notation void (*func)() pour définir un pointeur de fonction en C
  2. Utiliser le tableau de pointeurs de fonctions pour implémenter la fonctionnalité de programmation générique de type
Pointeur de fonction en C

Cet article présente l’utilisation d’un pointeur de fonction en C.

Utiliser la notation void (*func)() pour définir un pointeur de fonction en C

Les pointeurs de fonction sont une autre construction de la programmation C qui met en œuvre des fonctionnalités avancées comme l’appel dynamique de fonction, les structures qui incluent leurs propres méthodes similaires à la conception orientée objet, la programmation générique de type, etc. Notez que la déclaration des pointeurs de fonction peut avoir une syntaxe compliquée, à savoir, la notation void (*func)(void) déclare le pointeur à une fonction void qui ne prend aucun paramètre. Bien que nous assignions l’adresse de la fonction printInt, cela prend un seul argument int au pointeur de fonction de type void (*func)(void) dans l’exemple suivant. Une fois que le pointeur de fonction nommé func est défini, il peut être appelé avec la notation habituelle d’appel de fonction func(arg) ou avec l’opérateur de déréférencement (*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);
}

Production :

printed from printInt: 10233
printed from printDouble: 11.234000

Alternativement, nous pouvons définir un nouveau type d’alias d’un pointeur de fonction en utilisant typedef pour rendre le code plus lisible. Notez que les différents types de fonctions nécessitent des instructions typedef séparées. Dans l’exemple de code suivant, nous définissons un pointeur vers une fonction void sans aucun argument ; néanmoins, les adresses des fonctions printInt et printDouble sont toutes deux stockées dans la variable de type FuncPtr. Il convient de noter que l’adresse de la fonction spécifique peut être prise avec l’opérateur explicite & ou avec l’attribution implicite du nom de la fonction elle-même, comme le montre l’exemple suivant.

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

Production :

printed from printInt: 10233
printed from printDouble: 11.234000

Utiliser le tableau de pointeurs de fonctions pour implémenter la fonctionnalité de programmation générique de type

Comme les autres objets, on peut définir un tableau de pointeurs de fonction avec la notation [] entre crochets. Ce tableau peut être utilisé pour choisir et appeler facilement des fonctions spécifiques pendant l’exécution. Notez que nous utilisons le mot-clé _Generic, qui est switch comme une expression qui permet à l’utilisateur de choisir le cas spécifique en fonction de l’évaluation du type de l’expression de contrôle. En conséquence, nous implémentons l’exemple de code suivant, où la fonction print correspondante est appelée en fonction du type de la variable passée dans la condition switch. Notez que le type enum est également utilisé pour définir des valeurs constantes pour différents cas.

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

Production :

printed from printInt: 10233
printed from printDouble: 11.234000
Auteur: 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

Article connexe - C Pointer