Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

caster un (void *) vers un pointeur vers une fonction

1 réponse
Avatar
thomas.baruchel
Le titre du message appelle d'emblée une réponse: je crois que le
standard C prévoit le cas et le tient pour indéterminé, mais je
m'explique toujours pour avoir vos conseils.

Une fonction func1 qui n'a qu'un rôle d'interface DOIT appeler une
fonction principale, à laquelle elle donne d'une part l'adresse de
func2 et un pointeur (void *) pointant vers absolument n'importe quoi.
En fait, la fonction principale fait le plus gros du travail, et
appelle func2 à intervalle régulier en lui repassant le (void *).
Donc, la seule façon qu'a func1 de transmettre des données (et éventuellement,
mais ce n'est pas le problème ici, d'en récupérer par la suite) est de
gérer correctement le (void *).

Jusqu'ici aucun problème, et on peut faire des choses sophistiquées,
telles que passer à func2 plusieurs données de type très différents,
en jouant avec des casts.

MAIS, je bute sur la difficulté suivante: j'aimerais cette fois
transmettre de func1 à func2, d'une part une structure complexe,
d'autre part une fonction à exécuter.

Donc:
func1 {
void *arg[2];
...
arg[0] = &ma_jolie_fonction;
arg[1] = &ma_jolie_structure;
fonction_principale((void *) &arg);
}
func2 {
on récupère l'adresse de la fonction par
*(void **)arg
comment l'exécute-t-on ?
}

En fait, la fonction est de type:
unsigned char fonction(char *buf)

Bien sûr, j'ai essayé (dans func2):
((unsigned char (char *)) (*(void **)arg)) (buf)
où buf est du type char *
Mais gcc me retourne "cast specifies function type" (et c'est
ce que la norme prévoit, me semble-t-il).

Y a-t-il quelque chose à faire ? Me suis-je trompé ?

--
« nous devons agir comme si la chose qui peut-être ne sera pas devait
être » (Kant, Métaphysique des moeurs, doctrine du droit, II conclusion)

Thomas Baruchel <baruchel@laposte.net>

1 réponse

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', (Thomas Baruchel)
wrote:

Le titre du message appelle d'emblée une réponse: je crois que le
standard C prévoit le cas et le tient pour indéterminé, mais je
m'explique toujours pour avoir vos conseils.

Une fonction func1 qui n'a qu'un rôle d'interface DOIT appeler une
fonction principale, à laquelle elle donne d'une part l'adresse de
func2 et un pointeur (void *) pointant vers absolument n'importe quoi.


Pas n'importe quoi. D'un manière portable et définie, vers un objet
uniquement. Sinon, effectivement, c'est effectivement n'importe quoi...

En fait, la fonction principale fait le plus gros du travail, et
appelle func2 à intervalle régulier en lui repassant le (void *).
Donc, la seule façon qu'a func1 de transmettre des données (et
éventuellement, mais ce n'est pas le problème ici, d'en récupérer par la
suite) est de gérer correctement le (void *).


Pour des données, aucun problème. C'est le moyen traditionnellement utilisé
pour appemer une fonction 'callback'. (Comme la fonction de comparaison de
'qsort()').

Jusqu'ici aucun problème, et on peut faire des choses sophistiquées,
telles que passer à func2 plusieurs données de type très différents,
en jouant avec des casts.


Tout à fait. Cependant, le codeur doit être bien révéillé, car on travaille
sans filet. C'est le prix à payer pour l'utilisation des callbacks. Le code
est quasi universel (généraliste), mais la spécialisation a un coût. A ne pas
mettre entre les mains d'un archi-débutant...

MAIS, je bute sur la difficulté suivante: j'aimerais cette fois
transmettre de func1 à func2, d'une part une structure complexe,
d'autre part une fonction à exécuter.


Très simple. Comme toujours un simple void* suffit. Il suffit qu'il pointe
sur la structure adéquate, et que celle-ci soit valide au moment de l'appel.


Donc:
func1 {
void *arg[2];
...
arg[0] = &ma_jolie_fonction;
arg[1] = &ma_jolie_structure;
fonction_principale((void *) &arg);
}
func2 {
on récupère l'adresse de la fonction par
*(void **)arg
comment l'exécute-t-on ?
}

En fait, la fonction est de type:
unsigned char fonction(char *buf)

Bien sûr, j'ai essayé (dans func2):
((unsigned char (char *)) (*(void **)arg)) (buf)
où buf est du type char *
Mais gcc me retourne "cast specifies function type" (et c'est
ce que la norme prévoit, me semble-t-il).

Y a-t-il quelque chose à faire ? Me suis-je trompé ?


Pour des fonctions, ça ne va pas. Il faut par exemple

typedef unsigned char fun_f (char *buf);

typedef struct
{
func_f *f;
char *buf;
}
param_s;

func1
{
param_s param;

param.f = ma_jolie_fonction;
param.buf = l_adresse_du_buffer_de_ma_jolie_fonction;

fonction_principale (param);
}

func2 {void *p_user)
{
param_s *p_param = p;

if (p != NULL)
{
if (p_param->f)
{
unsigned char x = p_param->f (p_param->buf);
}
}
}

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/