C: Comment accéder à un pointeur de fonction stocké dans un pointeur vide (void *)?

Confus quant à la manière d’accéder à un pointeur de fonction stocké dans un pointeur vide (void *).


Disons que vous avez ceci:

void *functions[] = { &sqrt, // int ft_sqrt(int nb); &power, &logN, &factorial; }; // An array of void pointers, each storing a function pointer. 

Si je voulais accéder à la fonction sqrt , mon hypothèse serait la suivante:

(int (*)(int)) functions[0](x)

Mais ma supposition est fausse:

error: called object type 'void *' is not a function or function pointer


Alors, comment accéder à l’une de ces fonctions?

C’est une question de priorité de l’ opérateur : l’opérateur de l’appel de fonction a une priorité supérieure à celle de l’opérateur de transtypage.

Cela signifie que votre expression (int (*)(int)) functions[0](x) est vraiment égale à (int (*)(int)) (functions[0](x)) .

Vous devez explicitement append des parenthèses aux endroits appropriés pour lancer le pointeur: ((int (*)(int)) functions[0])(x) .


Une solution bien meilleure à l’OMI serait d’avoir un tableau de pointeurs vers des fonctions , de sorte que les éléments du tableau sont déjà du type correct:

 typedef int (*function_ptr)(int); function_ptr functions[] = { ... }; 

Alors aucun casting n’est nécessaire: functions[0](x) .

Ensuite, vous serez également à l’abri des problèmes mentionnés dans la réponse de Lundin .

Ssortingctement parlant, vous ne pouvez pas. Une conversion entre un pointeur de fonction et un pointeur void n’est pas possible. void* n’a jamais été un type de pointeur générique pour les pointeurs de fonction, mais uniquement pour les pointeurs d’object. Ce ne sont pas des types compatibles.

En pratique, tout pointeur aura très probablement la taille requirejse par le bus d’adresses du système. Par conséquent, les pointeurs d’object et les pointeurs de fonction auront très probablement la même représentation. Cela n’est cependant pas garanti par la norme, et il existe certains systèmes exotiques où cette équivalence n’est pas vraie. Vous pouvez donc choisir entre void* et un pointeur de fonction, mais ce qui va arriver est un comportement indéfini. Vous utiliserez des extensions non standard spécifiques au système.

Il serait légèrement préférable d’utiliser un type de pointeur de fonction tel que void (*)(void) comme pointeur générique. Vous pouvez convertir vers / à partir de différents pointeurs de fonction. Ce qui va arriver est spécifique au compilateur (comportement défini par l’implémentation). Autrement dit, le code ne sera toujours pas portable, mais au moins vous ne risquerez pas un blocage du programme en invoquant un comportement indéfini.