Reputation: 3287
I have to set a function pointer in a library API, such that it calls that function whenever it needs to perform a particular action.
int (*send_processor)(char*,int);
int setSendFunctor(int (*process_func)(char*,int))
{
send_processor = process_func;
}
In my main source, I have this function defined as the member function of a class,
int thisclass::thisfunction(char* buf,int a){//code}
thisfunction depends on other functions in thisclass. So I cannot separate it out of the class.
I cannot set the pointer to the member function in setSendFunctor, since inside the API, it is not assigning it to a pointer of member function, but to a regular function pointer send_processor.
Since thisclass is not a derived class, I cannot use virtual functions.
What is the best way to handle this?
Upvotes: 1
Views: 208
Reputation: 4028
Unfortunately, there is no way to pass a pointer-to-member to a C API like this because the C api does not know how to deal with the this pointer. If you can't change the library, you're kind of stuck.
If the API provides a method to pass an opaque "context" pointer through the library (as is done with things like CreateThread in Windows, where the parameter is treated by the OS as simply a pointer sized number which is passed on) then you should use a static member function, and use this context parameter to pass your this pointer through. In the static member function, cast the context parameter back to a pointer and call the member function through it. If the library can be changed by you, or you can get someone to change it, and it doesn't offer this functionality you should add it because this is the best way to bridge between objects and C.
Unfortunately, your API doesn't appear to provide a way of doing this. If your app is single threaded, and you can guarantee there is no reentrancy or multiple users of the library at the same time then you might be able to get away with storing the this pointer in a global or class static member then you could do that, and again use a static member function as the callback and call through the parameter.
A third approach, and absolute last resort, might be to create "thunk" objects, which are small objects which actually build the executable code to configure the this pointer and jump to the correct member function. On modern systems with DEP and things this is a difficult approach which is most likely not worth the hassle. The ATL library does this on windows, but it is hard and has caused them many security and update problems over the years.
Upvotes: 2
Reputation: 49311
If all else fails, and you have the case where your library only has the capability to take a function pointer with no client defined data, and you want to get callbacks on multiple objects, and the callback's lifecycles overlap, then you can use a trampoline.
The way I normally do this (actually, I've only ever had to do in a couple of times, so it's not common enough to be 'normally' doing it, since most libraries are sane enough to pass in some void* user data when you set a callback) is to compile a function with a hard-coded pointer in it:
int send_processor_trampoline ( char* buf, int a )
{
return ( ( thisclass* ) 0x12345678 ) -> thisfunction ( buf, a );
}
You can then inspect the machine code for this function ( in Windows by stepping into it and getting the value of the function pointer, then inspecting the memory at that location ). Typically you then have a couple of dozen bytes in which the location of the hard coded pointer is obvious. Change the pointer value and diff them if it's not. So a call the member function on a given object would have the same machine code, but the bytes for the hard coded pointer would be replaced with the bytes for the pointer to the receiver object.
To create trampolines at runtime given a pointer to a thisclass
object, grab some writeable, executable memory from the OS (usually you get this in chunks, so create a manager object for the trampolines so you don't use 4K for each 20 byte function), copy those bytes into it, replacing the bytes for the hard coded pointer with the object's pointer. You now have a pointer to a free function you can call which will call a member function on a specific object.
Upvotes: 1
Reputation: 56048
My usual way of handling this issue is to create a static function in my class that takes an explicit this
pointer as a parameter and then simply calls the member function. Sometimes the static function instead needs to closely follow the type signature the C library expects for a callback, in which case I cast the void *
that's common in such cases to the this
pointer I really want, then call the member function.
If the API does not have the facility for giving it a void *
that will then be given back to your callback, that API is broken and needs to be fixed. If you can't fix it, there are options involving global (or their little cousin static
) variables. But they're ugly.
I did, at one point, create a rather hackish templating system for creating these kinds of variables and sort of binding a static function to them that you could then pass to things that had this sort of API. But I'd have to go hunt it down and I'm not really convinced it offers any benefit over a plain old global.
A solution based on that idea without using templates would look something like this:
class InstanceBinder1 {
public:
static initialize(thisClass *instance, int (thisClass::*processor)(char *buf, int a)) {
instance_ = instance;
processor_ = processor;
}
static int processor(char *instance, int a) {
instance_->*processor_(buf, a);
}
private:
static thisClass *instance_;
static int (thisClass::*processor_)(char *buf, int a);
};
Then you could pass in &InstanceBinder1::processor
to the C library.
You would have to create a new class of this type for every separate instance of thisClass
you needed the C library to call into. This means the number of those instances will be determined at compile time, and there is no way around that.
Upvotes: 3
Reputation: 31435
I do not know exactly what the char* and the int are used for. If they are generated by the C API then there is nothing you can do as you have no way of passing in any "context" information.
If one of those refers to something you have passed in, and is getting called back to you, then you can map them back to your original "this" or a struct containing "this" plus some other char* or int.
Upvotes: 0
Reputation: 437366
The simplest approach would be to craft a couple of functions (a "caller" and a "setter") that set the value of a global variable. You would use the setter to set the value of the global at such a point in your program such that the object you want to call member functions on has been constructed. The caller will be passed to setSendFunctor
, and when called will forward the call to the value of the global variable.
I have intentionally not talked about the type of the global above; that can be whatever you might want it to be (a plain old function pointer, a member function pointer, a functor from Boost or some other library, or anything else that may be convenient).
Unfortunately I don't think there's a way to do this without a global, as the C API is pretty limiting.
Upvotes: 1