Pointeurs et fonctions
Mettre des fonctions dans des variables
On peut déclarer une variable f de type int(*)(void), c’est-à-dire une fonction qui ne prend rien et renvoie un entier :
int myFunction(){ return 42; }
int (*f)(void); // là on déclare un pointeur sur une fonction qui prend pas d'argument et renvoie un entier
f = &myFunction; // mais en fait le & est optionnel car de tte façon, ça ne veut rien dire d'autres
x = (*f)() // appel de la fonction
Pourquoi parle-t-on de pointeurs sur une fonction ?
Si myFunction est une fonction, alors &myFunction est l’adresse vers le code exécutable de la fonction myFunction.
f = &myFunction;
En mémoire
Plus précisément, voici une illustration de la mémoire d’un processus (au format ELF, Executable and Linkable Format, standard sous Linux).
- Le segment
textcontient le programme lui-même. Cette zone est en lecture seule. C’est là que se trouve le code exécutable de la fonctionmyFunctionet de toutes les fonctions présentes dans l’exécutable. - Le segment
datacontient les données (les constantes présentes dans le programme). - Le segment
bss(Block Started by Symbol) contient une zone pour les variables globales non initialisées (les variables initialisées sont directement dans le segmentdata) - puis on a le tas contient les données allouées avec
malloc, etc. - puis on a la pile contient les données des variables locales, les contextes des fonctions actuellement appelées
Passer des fonctions en paramètre
Du coup, on peut passer des fonctions en paramètre, par exemple pour renseigner comment trier un tableau d’entiers :
#include <stdlib.h>
int cmp(const void *pA, const void *pB)
{
/**
* ici on fait comme si c'était des entiers à trier
**/
int* intpA = pA;
int* intpB = pB;
int a = *intpA;
int b = *intpB;
return a - b;
/**
< 0 si "a < b"
= 0 si "a = b"
> 0 si "a > b"
*/
}
qsort(tableau, nbElementsTableau, nbOctetsElement, cmp)
Types pour les fonctions
Comme pour n’importe quel pointeur, il est important de savoir comment on utilise les données pointées.
Déclarer une variable
Voici le type d’une fonction :
int
(*)
(const void*, const void*)
En C, les types donnent une position pour mettre la variable déclarée. Vous avez toujours vu TYPE NOMVARIABLE;. Là on met la variable sur le partie verte :
int
(*f)
(const void*, const void*);
Définir un type
typedef
int
(*ComparisonFunction)
(const void*, const void*);
Et après on peut déclarer une variable f qui contient une fonction dont la signature est donnée par le type ComparisonFunction :
ComparisonFunction f;
ou
int cmp(const int *pA, const int *pB)
{
return *pA - *pB;
}
qsort(tableau, nbElementsTableau, nbOctetsElement, (ComparisonFunction) cmp)
map qui applique une fonction int f(int) sur un tableau d’entiers.
filter qui construit un tableau qui contient uniquement les éléments qui satisfont une condition données par une fonction bool condition(int).