 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
John Dumais Guest
|
Posted: Wed Dec 08, 2004 11:27 pm Post subject: Using static member functions as C callbacks |
|
|
Hello,
I'm using a commercial C library that parses particular kinds of files by
running callback functions defined in client code. The header file declares
a pointer to
function type using syntax similar to...
extern "C"{
typedef void (*Handler)(void*, const char*, const char**);
}
You connect a callback function to this C library by registering a function
pointer. I wanted to use a class in my C++ code as the callback function,
so I declared
a class like this...
class ParticularKindOfHandler{
public:
// declaration for handler function
static void MyHandler(void *v1, const char *v2, const char **v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
The GetHandler function causes one compiler to emit a warning something
like...
Anachronism: Using void(*)(void*, const char*, const char**) to initialize
extern "C" void(*)(void*, const char*, const char**)
So it would seem that using a static member function to implement the C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
If you would like to respond directly through email, remove the nospam_
prefix to my email address.
Thanks,
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Daniel Krügler (ne Spange Guest
|
Posted: Thu Dec 09, 2004 9:18 am Post subject: Re: Using static member functions as C callbacks |
|
|
Hello John Dumais,
John Dumais schrieb:
| Quote: | I'm using a commercial C library that parses particular kinds of files by
running callback functions defined in client code. The header file declares
a pointer to
function type using syntax similar to...
extern "C"{
typedef void (*Handler)(void*, const char*, const char**);
}
[snip] |
| Quote: | I wanted to use a class in my C++ code as the callback function,
so I declared
a class like this...
class ParticularKindOfHandler{
public:
// declaration for handler function
static void MyHandler(void *v1, const char *v2, const char **v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
The GetHandler function causes one compiler to emit a warning something
like...
Anachronism: Using void(*)(void*, const char*, const char**) to initialize
extern "C" void(*)(void*, const char*, const char**)
So it would seem that using a static member function to implement the C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
The compiler is right, because due to the different linkage declarations |
we (can have) two different
types here. The linkage of ParticularKindOfHandler::MyHandler ist extern
"C++" and it is implementation defined
whether this type is compatible to extern "C" linkage. Regrettably it is
not possible to declare a static
function member with different linkage although this is an artifical
restriction which should be fixed IMHO.
As a workaround I use a friend declared external function of wanted
linkage (with the disadvantage, that
this function can be called by everyone). Of course the friend
declaration is not always necessary (e.g.
from your example it is not possible to deduce whether it needs acces to
its wrapping class of not, but
I strongly assume that your implementation of
ParticularKindOfHandle::MyHandler needs private access) :
namespace Internal {
// declaration for handler function
extern "C" void MyPrivatePersonalHandler(void *v1, const char *v2, const char **v3);
}
class ParticularKindOfHandler{
public:
friend void ::Internal::MyPrivatePersonalHandler(void *v1, const char *v2, const char **v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
Greetings from Bremen,
Daniel Krügler
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Branimir Maksimovic Guest
|
Posted: Thu Dec 09, 2004 9:19 am Post subject: Re: Using static member functions as C callbacks |
|
|
John Dumais wrote:
| Quote: | Hello,
I'm using a commercial C library that parses particular kinds of
files by
running callback functions defined in client code. The header file
declares
a pointer to
function type using syntax similar to...
extern "C"{
typedef void (*Handler)(void*, const char*, const char**);
}
You connect a callback function to this C library by registering a
function
pointer. I wanted to use a class in my C++ code as the callback
function,
so I declared
a class like this...
class ParticularKindOfHandler{
public:
// declaration for handler function
static void MyHandler(void *v1, const char *v2, const char
**v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
The GetHandler function causes one compiler to emit a warning
something
like...
|
Well, if calling conventions of linkage specification does not match
you are in trouble. Problem is that c++ compiler is not obliged
to use same calling convention as c compiler.
If you wan't to compile such code with compilers that you don't know
linkage specification I wouldn't advise this approach.
This is a pain when trying to interface with c as even namespaces
cannot be used to differ function names:
eg
namespace One{
extern "C" void h(){}
}
namespace Two{
extern "C" void h(){}
}
This is ill formed as h has two definitions.
There is other solution for this problem. Usually all callback
functions uses void* to get some opaque data from user
so you can pass pointer to your object;
extern "C" void callback(void* p, const char* p1, const char**p2)
{
static_cast<Object*>(p)->handler(p1,p2); // in this case function
// does not have to be static at all
}
//
//.....
register_callback(&callback, new ConcreteObject);
//.......
If there is no such opaque data to be registered
with callback function, you are in trouble.
But first parameter of your callback is void* so I can smell
similar mechanism
Even if void* parameter is not provided by caller of register_callback
,there must be way to provide mappings between parameter and
object so you can lookup into some table of your callbacks
to find appropriate object.
Greetings, Bane.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
James Rafter Guest
|
Posted: Thu Dec 09, 2004 9:22 am Post subject: Re: Using static member functions as C callbacks |
|
|
| Quote: | So it would seem that using a static member function to implement the
C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
C++ mangles function names, C does not. The extern C declaration turns |
off name mangling so C++ can work with C.
Declare your callbacks functions outside of any class and declare them
extern C. You can hide these implementation details from users of
your class by having your .cpp file depend on them but not having your
..h file (explicitly) depend on them. That is, you can call these
functions by calling them from within your C++ functions. I'm sure
there are other ways also.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
L.Suresh Guest
|
Posted: Thu Dec 09, 2004 9:22 am Post subject: Re: Using static member functions as C callbacks |
|
|
The address of a static function in the class is an ordinary function
pointer. You can pass it to
C libraries. I guess you are getting stuck with the linkage.
--lsu
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Victor Bazarov Guest
|
Posted: Thu Dec 09, 2004 9:31 am Post subject: Re: Using static member functions as C callbacks |
|
|
John Dumais wrote:
| Quote: | I'm using a commercial C library that parses particular kinds of files by
running callback functions defined in client code. The header file declares
a pointer to
function type using syntax similar to...
extern "C"{
typedef void (*Handler)(void*, const char*, const char**);
}
You connect a callback function to this C library by registering a function
pointer. I wanted to use a class in my C++ code as the callback function,
so I declared
a class like this...
class ParticularKindOfHandler{
public:
// declaration for handler function
static void MyHandler(void *v1, const char *v2, const char **v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
The GetHandler function causes one compiler to emit a warning something
like...
Anachronism: Using void(*)(void*, const char*, const char**) to initialize
extern "C" void(*)(void*, const char*, const char**)
So it would seem that using a static member function to implement the C
callback is not a good idea. Can anyone explain why?
|
I think it is related to the fact that class members have C++ linkage, and
not "C" linkage.
| Quote: | Also, what's a better alternative?
|
Another function that you explicitly declare 'extern "C"' which just
forwards the call to the member function (if you're so inclined to have
the actual processing in the member).
V
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Stephan Brönnimann Guest
|
Posted: Fri Dec 10, 2004 1:46 am Post subject: Re: Using static member functions as C callbacks |
|
|
John Dumais wrote:
| Quote: | Hello,
I'm using a commercial C library that parses particular kinds of
files by
running callback functions defined in client code. The header file
declares
a pointer to
function type using syntax similar to...
extern "C"{
typedef void (*Handler)(void*, const char*, const char**);
}
You connect a callback function to this C library by registering a
function
pointer. I wanted to use a class in my C++ code as the callback
function,
so I declared
a class like this...
class ParticularKindOfHandler{
public:
// declaration for handler function
static void MyHandler(void *v1, const char *v2, const char
**v3);
// accessor to return pointer to callback function
virtual Handler GetHandler() { return MyHandler; }
};
The GetHandler function causes one compiler to emit a warning
something
like...
Anachronism: Using void(*)(void*, const char*, const char**) to
initialize
extern "C" void(*)(void*, const char*, const char**)
So it would seem that using a static member function to implement the
C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
If you would like to respond directly through email, remove the
nospam_
prefix to my email address.
Thanks,
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
John
AFAICS using static member functions is actually the
only way how you can implement such callbacks. Your
compiler however issues a very clever message:
| Quote: | From ParticularKindOfHandler::GetHandler() how are
going to access the this pointer of a particular |
instance of ParticularKindOfHandler for which the
member was called? Compare with the code that I'm using
to start a POSIX thread (sorry for the missing indentation:
Google beta messes it up)
#include <pthread.h>
extern "C" void* callThreadFunction(void* threadBase);
class ThreadBase {
public:
virtual void threadFunction() = 0;
void start();
// other stuff snipped
protected:
pthread_t thread_;
};
void ThreadBase::start()
{
pthread_create(&thread_, 0, callThreadFunction, this);
// ^
// note the this pointer which is passed as argument
// to callThreadFunction().
}
void* callThreadFunction(void* this_)
{
ThreadBase* thread = static_cast<ThreadBase*>(this_);
thread->threadFunction();
return 0;
}
Regards,
Stephan Brönnimann
[email]broeni (AT) osb-systems (DOT) com[/email]
http://www.osb-systems.com
Open source rating and billing engine for
communication networks.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Fri Dec 10, 2004 1:52 am Post subject: Re: Using static member functions as C callbacks |
|
|
In article <1102568722.325191.55350 (AT) z14g2000cwz (DOT) googlegroups.com>, James
Rafter <jjr2004a (AT) yahoo (DOT) com> writes
| Quote: | So it would seem that using a static member function to implement the
C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
C++ mangles function names, C does not. The extern C declaration turns
off name mangling so C++ can work with C.
Declare your callbacks functions outside of any class and declare them
extern C. You can hide these implementation details from users of
your class by having your .cpp file depend on them but not having your
.h file (explicitly) depend on them. That is, you can call these
functions by calling them from within your C++ functions. I'm sure
there are other ways also.
|
Yes.
1)
struct X {
static void foo(int);
// other
};
extern "C" {
inline void foo(int i){return X::foo(i);}
}
Will work, and work efficiently on almost all compilers.
2)
IIRC correctly the following syntax also works:
extern "C" {
typedef void (f_c)(int);
}
struct X{
static f_c foo;
// other
};
also works.
I would prefer not to use a friend declaration for this problem.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Fri Dec 10, 2004 2:08 am Post subject: Re: Using static member functions as C callbacks |
|
|
James Rafter wrote:
| Quote: | C++ mangles function names, C does not.
|
Most C compilers mangle names by prepending an underscore.
| Quote: | The extern C declaration turns
off name mangling so C++ can work with C.
|
That's the least important part of what it does. It tells the compiler
to generate the code so that it's compatible with C. That can affect the
calling convention and a bunch of other things. Name mangling typically
prevents linking code to places where it shouldn't be linked.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Daniel Krügler (ne Spange Guest
|
Posted: Fri Dec 10, 2004 11:00 am Post subject: Re: Using static member functions as C callbacks |
|
|
Hello Francis Glassborow,
Francis Glassborow schrieb:
| Quote: | IIRC correctly the following syntax also works:
extern "C" {
typedef void (f_c)(int);
}
struct X{
static f_c foo;
// other
};
also works.
I would prefer not to use a friend declaration for this problem.
|
That is a very nice solution and is far better than my workaround! This
also makes
my claims invalid that current C++ does not make it possible to declare
a static
member of user-defined linkage - Sorry.
Thanks,
Daniel
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Fri Dec 10, 2004 12:29 pm Post subject: Re: Using static member functions as C callbacks |
|
|
In article <g-OdnXMn9uFC-SXcRVn-rQ (AT) rcn (DOT) net>, Pete Becker
<petebecker (AT) acm (DOT) org> writes
| Quote: | That's the least important part of what it does. It tells the compiler
to generate the code so that it's compatible with C. That can affect the
calling convention and a bunch of other things. Name mangling typically
prevents linking code to places where it shouldn't be linked.
|
Actually I think you meant 'compatible with the calling conventions of a
companion C compiler if there is one.'
There is no requirement that there be such a C compiler, and the
calling/linkage conventions can, and do, vary between C implementations.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Fri Dec 10, 2004 3:53 pm Post subject: Re: Using static member functions as C callbacks |
|
|
In article <41b96354$0$6941$4d4ebb8e (AT) businessnews (DOT) de.uu.net>, "Daniel
Krügler (ne Spangenberg)" <dsp (AT) bdal (DOT) de> writes
| Quote: | Hello Francis Glassborow,
Francis Glassborow schrieb:
IIRC correctly the following syntax also works:
extern "C" {
typedef void (f_c)(int);
}
struct X{
static f_c foo;
// other
};
also works.
I would prefer not to use a friend declaration for this problem.
That is a very nice solution and is far better than my workaround! This
also makes
my claims invalid that current C++ does not make it possible to declare
a static
member of user-defined linkage - Sorry.
|
No need to apologise, too few people know how typedefs can be used to
solve this problem and allied ones. I have an advantage because I was
part of the small group who made linkage specification part of the type
of a function. Whilst we were convinced it was the right thing to do
(because there really were compilers where the C and C++ calling
conventions were different) we had to address issues such as the use of
static members as callbacks.
This is one of the places where typedef isn't just a shorthand but
supports something that can be done in no other way.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Fri Dec 10, 2004 5:01 pm Post subject: Re: Using static member functions as C callbacks |
|
|
Francis Glassborow wrote:
| Quote: | In article <g-OdnXMn9uFC-SXcRVn-rQ (AT) rcn (DOT) net>, Pete Becker
[email]petebecker (AT) acm (DOT) org[/email]> writes
That's the least important part of what it does. It tells the compiler
to generate the code so that it's compatible with C. That can affect the
calling convention and a bunch of other things. Name mangling typically
prevents linking code to places where it shouldn't be linked.
Actually I think you meant 'compatible with the calling conventions of a
companion C compiler if there is one.'
|
I meant what I said. If you would have said something different by all
means say it. In my view, excessive detail is just as bad as
insufficient detail. When someone's lost in the woods it doesn't help
them to describe what insects they're seeing in the bark on the trees.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Branimir Maksimovic Guest
|
Posted: Sat Dec 11, 2004 3:57 am Post subject: Re: Using static member functions as C callbacks |
|
|
Francis Glassborow wrote:
| Quote: | In article <1102568722.325191.55350 (AT) z14g2000cwz (DOT) googlegroups.com>,
James
Rafter <jjr2004a (AT) yahoo (DOT) com> writes
So it would seem that using a static member function to implement
the
C
callback is not a good idea. Can anyone explain why?
Also, what's a better alternative?
C++ mangles function names, C does not. The extern C declaration
turns
off name mangling so C++ can work with C.
Declare your callbacks functions outside of any class and declare
them
extern C. You can hide these implementation details from users of
your class by having your .cpp file depend on them but not having
your
.h file (explicitly) depend on them. That is, you can call these
functions by calling them from within your C++ functions. I'm sure
there are other ways also.
Yes.
1)
struct X {
static void foo(int);
// other
};
extern "C" {
inline void foo(int i){return X::foo(i);}
}
Will work, and work efficiently on almost all compilers.
2)
IIRC correctly the following syntax also works:
extern "C" {
typedef void (f_c)(int);
}
struct X{
static f_c foo;
// other
};
also works.
I would prefer not to use a friend declaration for this problem.
|
when I saw that following compiles I've dropped from my chair :0)
extern "C"{
typedef void func_t(void*);
typedef void func1_t(char*);
}
struct Test{
static func_t func;
static func1_t func;
};
extern "C"
void Test::func(void*)
{
}
extern "C"
void Test::func(char*)
{
}
int main()
{
Test::func((void*)0);
}
Heh, this news group is very, very usefull.
This solves A LOT of c<->c++ interfacing pains
Thak you.
Greetings, Bane.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
=3D?ISO-8859-1?Q?Falk_Tan Guest
|
Posted: Sun Dec 12, 2004 12:04 am Post subject: Re: Using static member functions as C callbacks |
|
|
Branimir Maksimovic wrote:
| Quote: | when I saw that following compiles I've dropped from my chair :0)
extern "C"{
typedef void func_t(void*);
typedef void func1_t(char*);
}
struct Test{
static func_t func;
static func1_t func;
};
|
As stated in =A7 7.5/4 "A C language linkage is ignored for the names of
class members and the member function type of class member functions."
and the 2 examples that follow, both functions will have C++ linkage.
A different problem is with templates:
________________________________________________________
#include <pthread.h> // Just for example, not part of C++ Standard
#include <cassert>
extern "C" { typedef void* pthread_entry_func(void*); }
template<typename T, void* (T::*memfun)()>
pthread_entry_func entry_routine; // declaration
template<typename T, void* (T::*memfun)()>
void* entry_routine(void* arg) // definition
{
return (static_cast<T*>(arg)->*memfun)();
}
/////////////////////////////////////////////////////////
class foo
{
pthread_t my_thread_id;
// ...
void* bar() { /* ... */ }
public:
foo(/* ... */)
{
int result = pthread_create(&my_thread_id, 0,
entry_routine<foo, &foo::bar>, // must be=
'extern "C"'!
this);
assert(result == 0);
}
~foo()
{
void* status = 0;
int result = pthread_join(my_thread_id, &status);
assert(result == 0);
}
}; // class foo
________________________________________________________
Unless I overlooked something, the Standard is silent on
the linkage specification of functions that are instantiated
from function templates, so it is not clear to me if the above
code is well-formed or not (provided the implementation knows
about pthreads, of course).
Comeau's on-line compiler (which correctly rejects assignments
between 'extern "C++" and 'extern "C"' function pointers) permits
assigning of pointers to templated functions declared as above to
'extern "C"' function pointers.
Falk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| 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
|
|