I am using a c dll in a c++ class. One of the member functions should call the following function that generates an interrupt and calls a service routine:
signed short __stdcall SetIrqConditions
(
signed short DevNum,
unsigned short bEnable,
unsigned int dwIrqMask,
void (__stdcall * funcExternalIsr)
(
signed short DevNum,
unsigned int dwIrqStatus
)
);
I am trying to call another member function of the same class as the last parameter of this function.(funcExternalIsr) When I tried to do this, the compiler complained that the function is not static. So I defined the callee function as a static function, but when I do that I cannot access other members of the class.
class myClass
{
public:
int counter;
void func1();
static void __stdcall func2(signed short DevNum, unsigned int Status);
};
void myClass::func1()
{
...
Result = SetIrqConditions(DevNum, TRUE, Mask, func2); --> no error here once func2 is static
}
void myClass::func2(signed short DevNum, unsigned int Status)
{
counter++; --> invalid use of member 'counter' in static member function
}
I tried many different ways and did some research but I can't seem to get this working, any pointers in the right direction would be appreciated.
Passing C++ class member function as a paremeter to C function
There is no way to do this with a non-static function, because C doesn't have such thing as a pointer to member function. C has only pointers to functions, and those cannot point to non-static member functions.
What you can do instead is to write a separate free wrapper function (or a static member function) where you call that non-static member function. Example:
void wrapper_function(demo args)
{
instance.member_function(args);
}
The remaining question is where to get the class instance to call within the wrapper. The options are in general:
Pass it as an argument to the wrapper. This is quite often an option with well designed C style callbacks that have a void* argument. That appears to not be the case here.
Use a variable with static storage. This is not ideal because global state is evil.
Create a local automatic variable within the wrapper. This is often not useful when the state of the instance needs to be accessed elsewhere.
Related
I have a class, Component, which has to interact with C code.
//// Component.h file ////
class Component{
public:
uint8_t getdevice1Value();
void setdevice1Value(uint8_t value);
uint8_t getdevice2Value();
void setdevice2Value(uint8_t uint8_t);
private:
uint8_t device1Value;
uint8_t device2Value;
}
The object of the class would be created when its relevant thread is created in some Application.cpp file:
///////Some function where the Component is used//////
createThread(){
Component myComponent; // Scope within the thread
// Some actions
}
Now comes my C code, which happens to be event driven. Within these functions, I would like to link my Class methods:
//// device1_event.c file ////
void command_get_device_value()
{
// code
// assign variable = Component::getdevice1Value() function
// code
}
void command_set_device_value()
{
// code
// call Component::setdevice1Value(variable) passing some variable
// code
}
Similar to device1_event.c file, I have another device2_event.c where I would like to map the function calls to getdevice2Value and setdevice2Value.
I looked at the questions Using a C++ class member function (cannot be static) as a C callback function or also this Pass a C++ member function to a C function, where a struct registers the context and the function pointers.
I have a constraint in my case of not being able to dynamic allocation. So, I cannot use the new operator.
Now I have a few questions regarding these:
Is the callback concept applicable in my case?
If the first question is a yes, then:
How do I go about implementing it. I am a bit confused about this. I mean the call-functions need to be placed within the C-functions and also I need to register them once the Component instance is created. How can I exactly do this?
How do I bring the callback functions to my C files?
In this question a struct was employed. Where do I declare the 'struct'? I did try declaring it in the Component.h file and introduced it as an extern within the device1_event.c file. But I get an incomplete type error.
The classical C way of passing callbacks is to pass two values: a pointer to the callback itself, and an opaque pointer which will be passed to the callback as an additional argument (take a look at qsort_r for example). When interfacing with C++, that opaque value may be used as instance pointer; you will only need to write a thin wrapper:
class B {
void my_callback(int arg);
static void my_callback_wrapper(int arg, void *u) {
((B*)u)->my_callback(arg);
}
};
// or even:
extern "C" void my_callback_wrapper(int arg, void *u) {
((B*)u)->my_callback(arg);
}
and pass a pointer to the wrapper, along with a pointer to the object, to the C part. Be careful to use the exact same class type on both sides and not base/derived classes, for example.
Note that while it may be possible to get a pointer to the (non-static) method itself, on some compilers (tested on MSVC a long time ago) they have a special calling convention so that the pointer will not be compatible with any normal function pointer.
This question already has answers here:
In C++, is it safe/portable to use static member function pointer for C API callbacks?
(4 answers)
Closed 4 years ago.
I am using a C library in a C++ application. The C SDK has functions that take a callback function pointer as an argument. The signature of these functions is usually like:
typedef int (* Func) (type1 c, type2 d);
I have my code structured using classes in C++. However, I can't pass any member functions to this function as callback because it doesn't accept int (MyClass::*)(type1 c, type2 d) and only accepts int (*)(type1 c, type2 d).
I'm getting around this by defining all my callbacks as static in the various classes and then passing them to the C library which then works.
I am still new to C++ so I'm not sure if this is the right solution? The code works, but I'd love to hear if I'm doing this wrong.
On most platforms your code is ever likely to encounter, your solution is fine. However, strictly speaking, there can be a platform where the C calling convention and C++ calling convention differ. On this platform, your code would not work.
The 100% correct solution (as opposed to the 99.9% correct one which you use) is to define a function with C language linkage as the callback. If you need this function to have member access to your class, it can then call a static member function in your class:
class MyClass
{
static int secret;
public:
static void callback() { secret = 42; }
};
extern "C" void callback() { MyClass::callback(); }
Note that it is considered good practice for authors of callback registration points (that is, authors of the library which will call you back) to provide a way for the user to associated void* data with the callback, which will be passed in as they call you. If your library allows that, you can use this void *user_data to pass in a pointer to your C++ class. With such a nicely-designed callback library, it could look like this:
class MyClass
{
int secret;
public:
void setSecret() { secret = 42; }
};
extern "C" void callback(void *userData) { static_cast<MyClass*>(userData)->setSecret(); }
MyClass mc;
int main()
{
cLibrary_registerCallback(&callback, &mc);
}
The member functions always implicitly get 'this' as their first argument. The use of static functions often works as static functions don't need this implicit argument. Please see Angew's answer with extern "C" thing to get 100% portability.
To call a non-static member function as a call back, you need to define a non-member function, which takes an instance as an argument, and calls the member function on that instance. Such C API's that use a function pointer callback also allow registering a void pointer to user defined data that will be forwarded to the call back. Use this pointer to pass the instance.
Instead of a named function, it is typical to use a lambda, because such simple wrapper is typically not reusable and has no need for a name.
I have a bit complicated class.
In this class I have a reference:
Private:
IEtApiPtr _pIEtApi;
IEtApiPtr is defined in a .tlh file:
_COM_SMARTPTR_TYPEDEF(IEtApi, __uuidof(IEtApi));
IEtApiPtr has a void named "SetRawDataCB"
virtual HRESULT __stdcall SetRawDataCB (
/*[in]*/ long address,
/*[in]*/ long userData,
/*[out,retval]*/ enum ApiError * pRetVal ) = 0;
I have defined a callback function in the class:
void CETAPI::RawDataCB(RawData& r, void* userData)
{
//do something
}
Now I want to install a callback using
_pIEtApi->SetRawDataCB((long)(__int64)(&RawDataCB),0,&result);
... the compiler tells me "Error C2276: Invalid operation for expression of a bound member function".
What did I do wrong here?
This doesn't work because RawDataCB is a member function not a global function. You can declare RawDataCB as a static function in the class as follows and this will work. However you will no longer have access to the this pointer (i.e. no member variables) unless you add it as a parameter to RawDataCB and perhaps make RawDataCB a friend to gain access to private data of the class as a member function would have. This can be done by updating the function declaration as follows:
class CETAPI {
static void RawDataCB(RawData& r, void* userData);
};
Alternatively, you can pass a pointer to RawDataCB as a member function pointer rather than a function pointer. Member function pointers can be manipulated as follows, so you will just pass an object of type RawDataCBType to SetRawDataCB.
typedef void (CETAPI::*RawDataCBType)(RawData&, void*); // typedef the member function pointer type
RawDataCBType pmf = &CETAPI::RawDataCB; // create and initialize a pointer to the member function
pCETAPIObject->*pmf(r, userData); // call the member function on an object of type CETAPI
Here is a good article that talks about member pointers.
In This case compiler founds problem in the syntax
use following line of code
pIEtApi->SetRawDataCB((long)(_int64)(&CETAPI::RawDataCB),0,&result);
see the link for more info Error code description
can I use thread in member function to call a member function for C++ in windows? If yes, how to implement it? Here is the sample
void Class::fun_1(void){
_beginthread(fun_2, 0, NULL); //This is the error line :: function call missing argument list; use '&Class::fun_2' to create a pointer to member
}
void Class::fun_2(void){
printf("hello");
}
Thanks
There are actually multiple issues here:
You can't pass a pointer to a member function as the routine to the _beginthread() function. The function requires a pointer to a global or static function.
Standard C++ requires that you fully qualify the member function name (even within the class) and use an & to obtain a pointer to the member (the compiler was complaining to you about this point).
Because you can't pass a member function pointer to _beginthread(), you need to create a wrapper global or static function to make it work. Here's one way to make that happen:
class MyClass
{
public:
void fun_1()
{
_beginthread(&MyClass::fun_2_wrapper, 0, static_cast<void*>(this));
}
private:
void fun_2()
{
printf("hello");
}
static void __cdecl fun_2_wrapper(void* o)
{
static_cast<MyClass*>(o)->fun_2();
}
};
Of course, you need to somehow guarantee that the MyClass object will still exist for as long as fun_2() is running, or not-so-good things will happen. If you much rather not have to worry about it, consider using Boost.Thread which does basically this and much more for you.
The usual way to do this is to use a static member function that calls the member function using a void pointer to the original object.
class Class
{
public:
void fun_1(void)
{
_beginthread( &Class::static_fun_2, 0, this );
}
void fun_2(void)
{
printf("hello");
}
private:
static void static_fun_2( void * args )
{
static_cast<Class*>(args)->fun_2();
}
};
However if you start needing to pass arguments to those functions things get a little more complicated. I'd look at using boost::thread and boost::bind instead of rolling your own.
my rusty C++ skills got a fail after:
#include <pcap.h>
...
void Sniff::pcap_listen() {
pcap_t *loc;
char *dev;
dev = pcap_lookupdev(errbuf);
loc = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
pcap_loop(loc,-1,pcap_callback,NULL);
}
error: argument of type ‘void
(Sniff::)(u_char*, const pcap_pkthdr*,
const u_char*)’ does not match ‘void
(*)(u_char*, const pcap_pkthdr*, const
u_char*)’
Adding/removing 'static' definition in .h: no effect.
++ another problem:
listener = g_thread_create(pcap_listen, NULL, FALSE, NULL);
Lot of variations of ::, &, this .. was tested, most informative message was:
src/main.cpp:281: error: argument of
type ‘void* (Sniff::)(void*)’ does not
match ‘void* ()(void*)’
You can't pass a pointer to a member function to something that's expecting a function pointer. Fundamentally a pointer to a member function is a completely different type than a function pointer. There is no trivial conversion between the two and can never be one as there's no this pointer, which is required to call a non-static member function.
Simply adding static doesn't technically solve the problem either, since it won't have C linkage, which could be a problem with a conforming implementation. In most implementations this is well behaved, but it is not portable in general and the portable solution requires using
extern "C" {
void my_callback() {
}
}
Update:
Given that both of the functions you're trying to call seem to take a void* "user argument" you can use this with a variable to pass a pointer to an instance of your class, e.g. something along these lines:
class CallbackHandler {
public:
void my_callback();
};
extern "C" {
void callback_wrapper(void *arg) {
static_cast<CallbackHandler*>(arg)->my_callback();
}
}
void start_pcap_listen(CallbackHandler* receiver) {
pcap_t *loc;
char *dev;
dev = pcap_lookupdev(errbuf);
loc = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
pcap_loop(loc,-1,callback_wrapper,receiver);
}
It's not pretty, but it works.
Member function and "free" function pointers are not interchangeable in C++. Your pcap_callback function appears to be an instance (non-static) member of class Sniff. If it is a static member, then you have to qualify it with the class name.
pcap_loop(loc,-1,Sniff::pcap_callback,NULL);
I think that what you should be gleaming from these compiler messages is that pointer to members are not the same as function pointers.
Whether making your member function static and thus converting its address from 'pointer to member' to 'pointer to function' will actually fix your problem is entirely dependent upon what your needs are.
You're passing a pointer to member function while the API expects a global function pointer. You've written that adding a static definition in the header has no effect, it should solve the problem since a static function isn't a member function (it's global). Could you share the reason it doesn't work when the function is static?
Commonly this can be done by using a ThreadFunction class. We will give it a non-virtual method "invoke" and a virtual method "run". Some variation of this will work:
class ThreadFunction
{
public:
virtual ~ThreadFunction();
void invoke( bool joinable );
protected: // or private
virtual void* run() = 0;
friend void * my_thread_func( void * );
GThread * gthread;
GError * error;
};
// In your cpp
void* my_thread_func( void * tf )
{
ThreadFunction * func = static_cast< ThreadFunction * >(tf);
return tf->run();
}
void ThreadFunction::invoke( bool joinable )
{
gthread = g_thread_create( my_thread_func, this, joinable, &error );
}
This is just an outline of the approach. You would create your thread to derive from ThreadFunction. (joinable may well be a feature of your implementation rather than a parameter passed in).