 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Eric Bart Guest
|
Posted: Thu Aug 26, 2004 1:03 pm Post subject: comment déclarer une fonction membre comme fonction callback |
|
|
Bonjour,
J'aimerais utiliser une fonction membre d'une classe comme une fonction
callback.
Par exemple pour utiliser une thread :
pthread_create (&th, NULL, MaClasse::MaFonction, NULL);
Si MaFonction est déclarée en static, ça fonctionne.
Mais est-ce possible avec une fonction membre non statique ?
Il faudrait pouvoir donner dynamiquement l'adresse de la fonction ... non ?
Merci
|
|
| Back to top |
|
 |
Loïc Joly Guest
|
Posted: Thu Aug 26, 2004 1:30 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
Eric Bart wrote:
| Quote: | Bonjour,
J'aimerais utiliser une fonction membre d'une classe comme une fonction
callback.
Par exemple pour utiliser une thread :
pthread_create (&th, NULL, MaClasse::MaFonction, NULL);
Si MaFonction est déclarée en static, ça fonctionne.
Mais est-ce possible avec une fonction membre non statique ?
|
Non.
| Quote: | Il faudrait pouvoir donner dynamiquement l'adresse de la fonction ... non ?
?? |
La technique classique la suivante (je détaille pas trop, c'est souvent
posé ici, regarde google pour plus de détails).
void threadFct (void* data)
{
MaClasse *mc = static_cast<MaClasse*> data;
mc->MaFonction();
}
int f()
{
MaClasse c;
// ...
pthread_create (&th, NULL, &threadFct, &c);
}
--
Loîc
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Thu Aug 26, 2004 2:15 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
Loïc Joly wrote:
| Quote: | Eric Bart wrote:
Bonjour,
J'aimerais utiliser une fonction membre d'une classe comme une fonction
callback.
Par exemple pour utiliser une thread :
pthread_create (&th, NULL, MaClasse::MaFonction, NULL);
Si MaFonction est déclarée en static, ça fonctionne.
|
Même ça n'est pas garanti, car à mon avis, pthread_create nécessite
comme argument un pointeur sur une fonction qualifiée 'extern "C"'.
Les fonctions C++ et C ne sont pas forcement interchangeables entre
elles, non seulement à cause du "name mangling" (qui n'intervient
pas lorsque l'appel se fait par pointeur) mais aussi parce que
la "calling convention" (Passage des paramètres dans des registres
ou sur la pile ? Dans quel ordre ? Qui fait le ménage sur la pile
au retour - la fonction appelée ou la fonction appelante ? Comment
passer la valeur de retour ?) peut différer entre les deux langages.
Certains compilateurs (par exemple GCC) acceptent la conversion
sans problème (soit ils utilisent la même convention d'appel, soit
ils génèrent un bout de code faisant les conversions nécessaires
s'il en y a besoin) mais cela reste non portable.
(À mon avis, ça serait *Bien* si une nouvelle release de la Norme
C++ mandatait un comportement satisfaisant dans tous les cas...)
| Quote: | Mais est-ce possible avec une fonction membre non statique ?
Non.
Il faudrait pouvoir donner dynamiquement l'adresse de la fonction ...
non ?
??
La technique classique la suivante (je détaille pas trop, c'est souvent
posé ici, regarde google pour plus de détails).
|
extern "C" // pour faire plus beau
| Quote: | void threadFct (void* data)
{
MaClasse *mc = static_cast<MaClasse*> data;
mc->MaFonction();
}
int f()
{
static
MaClasse c;
// ...
pthread_create (&th, NULL, &threadFct, &c);
}
|
Là, il faut faire attention à ce que la durée de vie de l'objet 'c'
ne soit pas plus courte que celle du (de la ?) "thread" crée(e) !
Donc il faudrait déclarer 'c' comme 'static' ou global (attention
alors à la création possible de plusieurs threads qui accèdent
au même objet), ou bien créer un objet dynamique qui ne devra être
détruit qu'une fois quand l[ea] thread en question est terminé(e).
Falk
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Thu Aug 26, 2004 2:48 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
"Eric Bart" <eb-adm (AT) eric-bart (DOT) pasdepubmerci.net> writes:
| Quote: | Il faudrait pouvoir donner dynamiquement l'adresse de la fonction
|
Si par « dynamiquement » tu entends « à l'exécution », c'est bien le
cas.
--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html
|
|
| Back to top |
|
 |
Eric Bart Guest
|
Posted: Thu Aug 26, 2004 4:30 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
| Quote: | Mais est-ce possible avec une fonction membre non statique ?
Non.
|
OK. Merci
|
|
| Back to top |
|
 |
Eric Bart Guest
|
Posted: Thu Aug 26, 2004 4:35 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
"drkm" <usenet.fclcxx (AT) fgeorges (DOT) org> wrote
| Quote: | "Eric Bart" <eb-adm (AT) eric-bart (DOT) pasdepubmerci.net> writes:
Il faudrait pouvoir donner dynamiquement l'adresse de la fonction
Si par « dynamiquement » tu entends « à l'exécution », c'est bien le
cas.
|
Oui c'est ce que je voulais dire.
Mon idée était mauvaise, je pensais pouvoir convertir l'adresse d'une fonction
membre en une adresse de fonction callback. Ca ne doit pas être possible ...
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Thu Aug 26, 2004 6:38 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
"Eric Bart" <eb-adm (AT) eric-bart (DOT) pasdepubmerci.net> writes:
| Quote: | Mon idée était mauvaise, je pensais pouvoir convertir l'adresse
d'une fonction membre en une adresse de fonction callback. Ca ne
doit pas être possible ...
|
Recherche dans les archives du groupe après quelque chose comme
"extern C callbak foncteur", tu devrais trouver pas mal de solutions.
C'est une question récurrente.
L'idée est que si le pointeur sur fonction doit pointer sur une
fonction extern "C", on n'a pas le choix, on doit créer une fonction
de ce type. Mais elle peut s'arranger pour déléguer à une classe
(fonction membre statique) ou un objet (fonction membre d'instance).
Souvent, les fonctions acceptant des callbacks C acceptent également
un pointeur sur void. On passe alors l'adresse d'un objet. La
fonction destinée à être enregistrée caste alors son argument vers le
type ad-hoc, et appelle la fonction membre ad-hoc de cette objet.
--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Aug 27, 2004 7:37 am Post subject: Re: comment déclarer une fonction membre comme fonction cal |
|
|
Falk Tannhäuser <falk.tannhauser (AT) crf (DOT) canon.fr> wrote
| Quote: | Loïc Joly wrote:
Eric Bart wrote:
J'aimerais utiliser une fonction membre d'une classe comme une
fonction callback.
Par exemple pour utiliser une thread :
pthread_create (&th, NULL, MaClasse::MaFonction, NULL);
Si MaFonction est déclarée en static, ça fonctionne.
Même ça n'est pas garanti, car à mon avis, pthread_create nécessite
comme argument un pointeur sur une fonction qualifiée 'extern "C"'.
|
Tout à fait.
| Quote: | Les fonctions C++ et C ne sont pas forcement interchangeables entre
elles, non seulement à cause du "name mangling" (qui n'intervient pas
lorsque l'appel se fait par pointeur) mais aussi parce que la "calling
convention" (Passage des paramètres dans des registres ou sur la pile
? Dans quel ordre ? Qui fait le ménage sur la pile au retour - la
fonction appelée ou la fonction appelante ? Comment passer la valeur
de retour ?) peut différer entre les deux langages. Certains
compilateurs (par exemple GCC) acceptent la conversion sans problème
(soit ils utilisent la même convention d'appel, soit ils génèrent un
bout de code faisant les conversions nécessaires s'il en y a besoin)
mais cela reste non portable.
|
Accepter le code, c'est une extension non conforme, parce que la norme
exige un diagnostique dans ce cas-ci.
| Quote: | (À mon avis, ça serait *Bien* si une nouvelle release de la Norme C++
mandatait un comportement satisfaisant dans tous les cas...)
|
Le problème, c'est que la norme C++ ne peut pas imposer des contraints
sur le C. Le but de l'« extern "Langage" », c'est justement de dire au
compilateur qu'il faut utiliser d'autres conventions. Je ne vois pas
comment la norme C++ pourrait imposer que les conventions soient les
même en C et en C++ -- il ne peut qu'imposer les contraints sur le C++.
Dans la pratique, il faut dire aussi qu'il y a eu des implémentations où
les conventions C et C++ différaient. Ce n'est donc pas qu'une
considération théorique.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Aug 27, 2004 8:20 am Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
"Eric Bart" <eb-adm (AT) eric-bart (DOT) pasdepubmerci.net> wrote
| Quote: | J'aimerais utiliser une fonction membre d'une classe comme une
fonction callback.
Par exemple pour utiliser une thread :
pthread_create (&th, NULL, MaClasse::MaFonction, NULL);
Si MaFonction est déclarée en static, ça fonctionne.
Mais est-ce possible avec une fonction membre non statique ?
|
Ce n'est pas possible avec une fonction membre, statique ou non. Il faut
que ce soit une fonction libre déclarée « extern "C" ».
| Quote: | Il faudrait pouvoir donner dynamiquement l'adresse de la fonction ...
non ?
|
Il faut en prendre l'adresse, parce que c'est l'adresse d'une fonction
qu'attend pthread_create. Mais où en est le problème :
extern "C"
void*
threadStarter( void* p )
{
return static_cast< MaClass* >( p )->maFonction() ;
}
pthread_create( &th, NULL, &threadStarter, &maThread ) ;
Tiens, une question pour les experts : est-ce qu'une fonction templatée
puisse être « extern "C" » ? Parce que je verais bien un template pour
« threadStarter », ci-dessus.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
Jean-Marc Bourguet Guest
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Aug 27, 2004 10:23 am Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: | Tiens, une question pour les experts : est-ce qu'une fonction templatée
puisse être « extern "C" » ? Parce que je verais bien un template pour
« threadStarter », ci-dessus.
Je ne sais pas si je suis un expert, mais |
____________________________________________________
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T>
struct wrap_pthreadEntry
{
static pthreadEntryFunc externCfunc;
};
template<typename T>
void* wrap_pthreadEntry<T>::externCfunc(void* p)
{
return static_cast<T*>(p)->MaFonction();
}
_____________________________________________________
est accepté par g++, ainsi que Comeau et Dinkum en ligne (je sais que cela
ne constitue pas une preuve...)
Avec g++, cela me permet de faire
_____________________________________________________
#include <iostream>
#include <ostream>
#include <pthread.h>
#include <cassert>
struct foo
{
foo* MaFonction() { std::cout << "Hello world!" << std::endl; return this; }
};
foo f;
int main()
{
pthread_t thr1;
if(pthread_create(&thr1, NULL, &wrap_pthreadEntry
{
std::cerr << "Error during pthtread_create" << std::endl;
return EXIT_FAILURE;
}
void* pthread_return_value = 0;
pthread_join(thr1, &pthread_return_value);
assert(pthread_return_value == &f);
return EXIT_SUCCESS;
}
_____________________________________________________
On pourrait certainement faire quelque chose de plus balèze,
prenant un pointeur sur la fonction membre en paramètre,
puis qui encapsule aussi l'appel à pthread_create, de manière
à empêcher que quelqu'un passe un pointeur sur un type incompatible
comme quatrième argument ...
Falk
Falk
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Aug 27, 2004 12:03 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
Falk Tannhäuser wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote:
Tiens, une question pour les experts : est-ce qu'une fonction templatée
puisse être « extern "C" » ? Parce que je verais bien un template pour
« threadStarter », ci-dessus.
Je ne sais pas si je suis un expert, mais
____________________________________________________
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T
struct wrap_pthreadEntry
{
static pthreadEntryFunc externCfunc;
};
template
void* wrap_pthreadEntry
{
return static_cast<T*>(p)->MaFonction();
}
_____________________________________________________
est accepté par g++, ainsi que Comeau et Dinkum en ligne (je sais que cela
ne constitue pas une preuve...)
|
§ 7.5/4 "A C language linkage is ignored for the names of class members
and the member function type of class member functions.functions. [Example:
extern "C" typedef void FUNC_c();
class C {
void mf1(FUNC_c*); // the name of the function mf1 and the member
// function’s type have C++ language linkage; the
// parameter has type pointer to C function
FUNC_c mf2; // the name of the function mf2 and the member
// function’s type have C++ language linkage
static FUNC_c* q; // the name of the data member q has C++ language
// linkage and the data member’s type is pointer to
// C function
};
..."
Donc ce que j'imaginais ne marche pas (au moins sous un compilateur
strictement conforme) :-(
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Aug 27, 2004 12:44 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
// Deuxième tentative :
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T> pthreadEntryFunc threadStarter; // declaration
template<typename T> void* threadStarter( void* p ) // definition
{
return static_cast<T*>( p )->maFonction() ;
}
struct foo
{
foo* maFonction() { std::cout << "Hello world!" << std::endl; return this; }
};
extern "C"
{
void* (*pf)(void*) = 0;
}
void* toto(void* p) { return p; } // extern "C++
int main()
{
pf = &threadStarter
// g++ and Dinkum[EDG/C++]
pf = &toto; // Accepted by g++ and Dinkum[VC++/C++], refused (correctly,
// according to the standard) by Comeau and Dinkum[EDG/C++]
return 0;
}
___________________________________________________________________________
Je ne sais pas qui a raison.
Dinkum[VC++/C++] <http://www.dinkumware.com/exam/> me fait
error C2783: 'pthreadEntryFunc threadStarter' : could not deduce template argument for 'T'
error C2563: mismatch in formal parameter list
error C2568: '=' : unable to resolve function overload
could be 'pthreadEntryFunc threadStarter'
Falk
|
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Sat Aug 28, 2004 4:21 pm Post subject: Re: comment déclarer une fonction membre comme fonction call |
|
|
Falk Tannhäuser <falk.tannhauser (AT) crf (DOT) canon.fr> writes:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote:
Tiens, une question pour les experts : est-ce qu'une fonction
templatée puisse être « extern "C" » ? Parce que je verais bien un
template pour « threadStarter », ci-dessus.
Je ne sais pas si je suis un expert, mais
____________________________________________________
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T
struct wrap_pthreadEntry
{
static pthreadEntryFunc externCfunc;
};
template
void* wrap_pthreadEntry
{
return static_cast<T*>(p)->MaFonction();
}
_____________________________________________________
|
Tiens, je n'avais pas pensé à la possibilité d'un typedef. La raison
pourquoi une fonction membre statique ne peut pas être « extern "C" »
est simple : il n'y a pas de syntaxe pour dire qu'elle est « extern
"C" ». Il n'y a rien de fondamental qui l'interdit.
N'empêche que je crois que c'est une question pour comp.std.c++ ?
Seulement une question : comment est-ce que tu fais pour définir la
fonction. (Si je me rappelle bien, tu n'as pas droit au typedef dans la
définition.)
| Quote: | est accepté par g++, ainsi que Comeau et Dinkum en ligne (je sais
que cela ne constitue pas une preuve...)
|
G++, en tout cas, ne traite pas le « extern "C" » comme faisant partie
du type.
À vrai dire, il faudrait avoir un compilateur où les conventions d'appel
était réelement différentes entre les deux langages, pour voir ce que ça
donne à l'exécution.
--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|