So below is a basic idea of what I'm trying to do.
I have an external library that I would like to use in an existing project.
I cannot change anything in the external library or the main function in the existing project of course.
The problem I face is how to pass a callback function I make in my class to this external function as a pointer to function. At the same time, this callback function has to have access to members of the class so I cannot simply make it static. How can I do it?
Class ExternalClass //This I cannot mess with.
{
//somestuff
void ExternalFunc (void(* callback)(int, const void*), const void *);
}
Class MyClass
{
//somestuff
ExternalClass m_ExObj;
void Callback(int x, const void *p){
//dosomething
//How do I use this pointer ?
}
void MyFunc(){
m_ExObj.ExternalFunc(/*Some way to put MyClass::Callback() in here*/)
}
}
The callback you have shown does not allow a user-defined value to be passed to it (otherwise you could use that for passing around your object pointer). It expects a standalone non-class function, so you have two options:
1) if the callback only ever calls into a single object at one time, then you can store the object pointer in a global or static variable, and then use a standalone function (or static class method) as the callback and have it use the global/static pointer to call your class method:
class MyClass
{
//somestuff
ExternalClass m_ExObj;
void Callback(int x)
{
//dosomething
}
static MyClass* objForCallback;
static void exObjCallback(int x) { objForCallback->Callback(x); }
void MyFunc()
{
objForCallback = this;
m_ExObj.ExternalFunc(&exObjCallback);
}
};
2) if you need to have callbacks for multiple objects at a time, you will have to wrap your class method inside a per-object thunk, where each thunk knows which object to call into, and then you use the thunks as callbacks. This is a more advanced technique, requiring an understanding of x86/x64 assembly and calling conventions, as you have to allocate memory dynamically and populate it with assembly instructions for each thunk to execute at runtime. For example, at least on Windows 32bit:
#pragma pack(push, 1)
struct MyThunk
{
unsigned char PopEAX_1; // POP the caller's return address off the stack
unsigned char PushThis; // PUSH the object 'this' pointer on to the stack
void *ThisValue;
unsigned char PushEAX_1; // PUSH the caller's return address back on to the stack
unsigned char Call; // CALL the callback function
__int32 CallAddr;
unsigned char PopEAX_2; // POP the caller's return address off the stack
unsigned char AddESP[3]; // Remove the object 'this' pointer from the stack
unsigned char PushEAX_2; // PUSH the caller's return address back on to the stack
unsigned char Return; // return to the caller
};
#pragma pack(pop)
typedef void (*CallbackType)(int);
class MyClass
{
CallbackType exObjCallback;
MyClass()
{
MyThunk *thunk = (MyThunk*) VirtualAlloc(NULL, sizeof(MyThunk), MEM_COMMIT, PAGE_READWRITE);
if (thunk)
{
thunk->PopEAX_1 = 0x58;
thunk->PushThis = 0x68;
thunk->ThisValue = this;
thunk->PushEAX_1 = 0x50;
thunk->Call = 0xE8;
thunk->CallAddr = reinterpret_cast<__int32>(Callback) - (reinterpret_cast<__int32>(&thunk->Call) + 5);
thunk->PopEAX_2 = 0x58;
thunk->AddESP[0] = 0x83;
thunk->AddESP[1] = 0xC4;
thunk->AddESP[2] = 0x04;
thunk->PushEAX_2 = 0x50;
thunk->Return = 0xC3;
DWORD dwOldProtect;
VirtualProtect(thunk, sizeof(MyThunk), PAGE_EXECUTE, &dwOldProtect);
FlushInstructionCache(GetCurrentProcess(), thunk, sizeof(MyThunk));
exObjCallback = (CallbackType) thunk;
}
}
~MyClass()
{
if (exObjCallback)
VirtualFree(exObjCallback, 0, MEM_RELEASE);
}
//somestuff
ExternalClass m_ExObj;
// NOTE: pCtx is the return address inside of ExternalFunc()
// where the callback is being called from. Because the
// callback is using the __cdecl calling convention, the
// thunk needs to remember this value and restore it after
// Callback() exits. Passing it as a parameter to Callback()
// is a quick-n-dirty way for the thunk to do that...
static void __cdecl Callback(void *pCtx, MyClass *pThis, int x)
{
//dosomething with pThis
}
void MyFunc()
{
if (exObjCallback)
m_ExObj.ExternalFunc(exObjCallback, ...);
}
};
When ExternalFunc() calls its callback, it will be calling the thunk, executing the instructions it contains. The thunk above is injecting the object's this pointer into the call stack as a parameter for Callback() as if ExternalFunc() had called it directly.
Update: in lieu of new information about the callback actually accepting a user-defined value, that greatly simplifies things:
class MyClass
{
//somestuff
ExternalClass m_ExObj;
static void Callback(int x, const void *p) {
MyClass *pThis = (MyClass*) p;
//dosomething with pThis
}
void MyFunc() {
m_ExObj.ExternalFunc(&Callback, this);
}
};
Related
This question already has answers here:
How can I pass a class member function as a callback?
(13 answers)
Closed 2 years ago.
I've got a class named tmc, which now contains (among other things, which are not relevant here) a private constructor, a static factory method, and an instance method named ReadLoop (void*):
extern "C" {
#include <pigpiod_if2.h>
}
class tmc {
public:
static tmc* Initialize ();
static int main ();
private:
void *ReadLoop (void *params);
tmc ();
pthread_t *tmc_receiver_reader;
};
tmc::tmc ()
: tmc_receiver_reader (start_thread (tmc::ReadLoop, NULL))
{
}
void* tmc::ReadLoop (void *params)
{
return params;
}
tmc* tmc::Initialize ()
{
tmc* instance = new tmc ();
return instance;
}
int tmc::main ()
{
return (tmc::Initialize ()) == NULL ? 0 : 1;
}
The issue is now the following: How shall I use the ReadLoop as a function pointer for use with the start_thread () function contained in pigpiod_if2? The code shown here doesn't compile because of the following error:
error: invalid use of non-static member function ‘void* tmc::ReadLoop(void*)’
tmc_receiver_reader (start_thread (tmc::ReadLoop, NULL))
I've seen several questions here at SO with the same error message, but none of them was about a pointer to a non-static member method given to a C function. Please note that even if the object created here is a singleton, I can't make ReadLoop () static. I'm using the g++ 6.5.0 on Raspbian Buster. Thank you.
There is simply no way to use a non-static class method where a standalone function is expected. They are not compatible.
You are going to have to use a static or non-member proxy function instead. Fortunately, start_thread() allows you to pass a user-defined parameter to the function, so you can use that to pass the this pointer of your tmc instance, eg:
class tmc {
...
private:
static void* ReadLoopProxy(void *params);
void* ReadLoop();
tmc ();
pthread_t *tmc_receiver_reader;
};
tmc::tmc ()
: tmc_receiver_reader (start_thread (tmc::ReadLoopProxy, this))
{
}
void* tmc::ReadLoopProxy(void *params)
{
return static_cast<tmc*>(params)->ReadLoop();
}
void* tmc::ReadLoop()
{
return NULL;
}
...
Luckily the C interface provides a void* pass-back to help with this. You can use that to point to the correct tmc object:
extern "C" void* tmc_pigpio_ReadLoop_callback(void* userdata);
class tmc {
// ...
private:
void* ReadLoop();
friend void* tmc_pigpio_ReadLoop_callback(void*);
// ...
};
void* tmc_pigpio_ReadLoop_callback(void* userdata)
{
auto* tmcp = static_cast<tmc*>(userdata);
return tmcp->ReadLoop();
}
// Note "this" passed to start_thread.
tmc::tmc ()
: tmc_receiver_reader (start_thread (tmc_pigpio_ReadLoop_callback, this))
{
}
Or if you were already using the void* userdata for something different, add a tmc* pointer to a struct it points at, or create a new struct containing a tmc* pointer and the other data to pass.
The Settings: I'm building an architecture that has parts in C and part in C++.
In my Architecture I have:
A data_io(C) which gets data sends it to a processor callback and outputs the processed data.
A data_processor(C) which takes care of processing data and changes on-demand.
A settings_manager(C++) which decides which processor to use.
The relationship is as follows:
The settings_manager object is instantiated, inside it initializes the data_processor with a default processor function, and then initializes the data_io sending to it a processing_callback_function (defined in the settings_manager, but internally referencing a data_processor function) which is then used to process the data when the data_io starts. (so, the data_io receives the processing_callback_function only once at initialization and does not care about what the callback does inside, it just generates data, calls the processing_callback_function and outputs processed data)
While the system is working, the settings_manager may decide to change the data_processor type of processing, so it changes the processing_callback_function to call a different data_processor function.(the data_io does not know about it and continues working)
Here is the basic implementation:
data_io.c:
typedef void (* ProcessorCallback_t)(float *, int);
ProcessorCallback_t processorCallback;
data_io_init(ProcessorCallback_t callback) {
processorCallback;
...init all other stuff like data pointer...
}
data_io_loop() {
bufSize = readData(&data);
processorCallback(&data, bufSize);
writeData(&data, bufSize);
}
data_procesor.c:
void data_processor_init() {
...initialization routine...
}
void data_processor_proc1(float *data, int bufSize) {
...data process...
}
void data_processor_proc2(float *data, int bufSize) {
...data process...
}
settings_manager.cpp:
void SettingsManager::start() {
data_processor_init();
this->processing_function = &data_processor_proc1;
//THIS IS MY QUESTION! HOW TO PASS THE processing_callback_function TO data_io_init
data_io_init(&SettingsManager::processing_callback_function);
... here starts a new thread to run loop below...
//while(this->condition) {
// data_io_loop();
//}
}
void SettingsManager::changeProcessorType(int processorType) {
switch(processorType) {
case 1:
this->processing_function = &data_processor_proc1;
break;
case 2:
this->processing_function = &data_processor_proc2;
break;
}
}
void SettingsManager::processing_callback_function(float *data, int buffer_size) {
this->processing_function(data, buffer_size);
}
My Questions:
1. How should I pass the processing_callback_function C++ member function to the data_io_init C function?
when I do the following:
data_io_init(&SettingsManager::processing_callback_function);
I get the following error:
"Incompatible pointer types 'ProcessorCallback_t' and 'void(Engine::*)(float*,int)'"
Well the error is obvious, the types are different as the second is a member function and is part of the instance of the object.
I've read that I should make the processing_callback_function static, but I'm not sure if it is the right approach.
What is the appropriate way to handle this kind of things, are there any patrons that might be useful to read, or coding strategies that may be related?
A non-static class method has a hidden this pointer that a free-standing function does not. So such, you can't pass a non-static class method where a free-standing function is expected.
The best solution in this situation is to allow the C++ code to pass a user-defined value to the C code, and then have the C code passes that value back to the C++ code. That way, the C++ code can pass around its this pointer. For example:
data_io.h:
typedef void (* ProcessorCallback_t)(float *, int, void *);
void data_io_init(ProcessorCallback_t callback, void *userdata);
void data_io_loop();
data_io.c:
ProcessorCallback_t processorCallback;
void *processorUserData;
void data_io_init(ProcessorCallback_t callback, void *userdata) {
processorCallback = callback;
processorUserData = userdata;
...init other stuff as needed ...
}
void data_io_loop() {
...
processorCallback(&data, bufSize, processorUserData);
...
}
Then SettingsManager can do this:
settings_manager.h:
typedef void (* ProcessorFunc_t)(float *, int);
class SettingsManager
{
private:
ProcessorFunc_t processing_function;
...
static void processing_callback_function(float *data, int buffer_size void *userdata);
public:
void start();
...
};
settings_manager.cpp:
#include "data_io.h"
void SettingsManager::start()
{
...
data_io_init(&SettingsManager::processing_callback_function, this);
...
}
void SettingsManager::processing_callback_function(float *data, int buffer_size void *userdata)
{
static_cast<SettingsManager*>(userdata)->processing_function(data, buffer_size);
}
Or this (as the above is technically undefined behavior, but it does work in most compilers. The below is more standards compliant):
settings_manager.h:
typedef void (* ProcessorFunc_t)(float *, int);
class SettingsManager
{
...
public:
ProcessorFunc_t processing_function;
void start();
...
};
settings_manager.cpp:
#include "data_io.h"
void processing_callback_function(float *data, int buffer_size void *userdata)
{
static_cast<SettingsManager*>(userdata)->processing_function(data, buffer_size);
}
void SettingsManager::start()
{
...
data_io_init(&processing_callback_function, this);
...
}
1) Write everything in C++. Use std::function as a callback. This is the best way to handle this. Do you really have a performance issue? Have you measured it? C++ is not that slow. Problems that you will have by mixing two lanuage styles will bring more problems.
2) Functions are the same in C and C++. You can always do the following:
class Cls {
public:
void callback() {}
};
void Cls_callback(void* ptr) {
reinterpret_cast<Cls*>(ptr)->callback();
}
And then pass that Cls_callback as the C callback.
3) You may make Cls_callback a static method of Cls and that way it will have access to private members of Cls:
class Cls {
public:
static void Cls_callback(void* ptr) {
Cls* self = reinterpret_cast<Cls*>(ptr);
self->i += 1;
}
private:
int i;
};
But keep in mind, that this actually is an UB. It will work, it is slightly less code than variant 2, but technically speaking, standard does not guarantee that this will work.
P.S. Yet again, don't mix styles. Use C++ everywhere.
I found several similar questions, but the solutions didn't suit my case.
In a C++ method, I call a C api, which takes a callback as one of its parameter.
class A
{
herr_t methodA(some parameters) {....}
void methodB(some parameters)
{
....
int status = CAPI(other parameters, callback, last parameter);
}
};
The prototype of CAPI is
herr_t CAPI( some parameters, H5L_iterate_t op, other parameters);
H5L_iterate_t is defined by
herr_t (*H5L_iterate_t)( hid_t g_id, const char *name,
const H5L_info_t *info, void *op_data)
methodA has the same signature as H5L_iterate_t.
In methodB,
status = CAPI(..., **(H5L_iterate_t )std::bind(&A::methodA, this,
std::placeholders::_1)**, ...);
The compile error I got was "Can't convert from ... to H5L_iterate_t". I'm wondering what's the right way to pass the non static member function as a callback.
Thanks in advance.
C APIs offering a callback almost always follow this pattern:
extern "C"
{
typedef void(*callback_function)(void* data);
typedef int handle_type;
void do_something_with_callback(handle_type, callback_function, void *data);
}
The idea being that whatever you pass as the data argument when do_something_with_callback is called, will be passed to the callback_function.
You can use this user data to pass a pointer to your c++ object's address, which you can then cast back to a pointer to your object type:
struct my_object
{
void initiate()
{
// call the C interface, passing our c-style callback function with
// a pointer to this class as the user data
do_something_with_callback(handle_, &callback_launch_function, this);
}
private:
static void callback_launch_function(void * data) {
// the data will always be a pointer to my_object -
// because that's what we passed.
auto self = reinterpret_cast<my_object*>(data);
self->handle_it();
}
// this is our c++style callback
void handle_it()
{
}
handle_type handle_;
};
I try to implement an array of function pointers in an singleton owning a thread.
In the thread function I get an error, telling me that a member has to be relative to an object. More in the commentline...
Header:
typedef struct{
int action;
HWND handle;
}JOB;
class Class{
public:
enum Action { 1,2 };
private:
JOB m_currentJob;
queue<JOB> Jobs;
static DWORD WINAPI ThreadFunction(LPVOID lpParam);
void (Class::*ftnptr[2])(JOB Job);
void Class::ftn1(JOB Job);
void Class::ftn2(JOB Job);
// Singleton pattern
public:
static Class* getInstance(){
if(sInstance == NULL)
sInstance = new Class();
return sInstance;
}
private:
Class(void);
~Class(void);
static Class* sInstance;
};
Body:
#include "Class.h"
Class* Class::sInstance = NULL;
Class::Class(){
this->ftnptr[0] = &Class::ftn1;
this->ftnptr[1] = &Class::ftn2;
}
DWORD WINAPI Class::AutoplayerThreadFunction(LPVOID lpParam)
{
Class *pParent = static_cast<Class*>(lpParam);
while(true){
(pParent->*ftnptr[pParent->m_currentJob.action])(pParent->m_currentJob);
/* The line above causes the compiler error. Curious to me is that
* neither "pParent->m_currentJob" nor "pParent->m_currentJob" cause
* any problems, although they are members too like the ftnptr array.
*/
}
}
void Class::ftn1(JOB Job){}
void Class::ftn2(JOB Job){}
A call via getInstance from the SingletonPattern doesnt make it any better.
Any suggestions?
ftnptr is a member of Class. However, you access it directly. That is, pParent->*ftnptr[...] means "access the member of pParent designated by the pointer ftnptr[...]", but it doesn't imply that ftnptr too is a member of pParent.
The correct code is (pParent->*(pParent->ftnptr[...]))(...). But I would recommend extracting the array index expression from that:
auto fnptr = pParent->ftnptr[...];
(pParent->*fnptr)(...);
I think it might be how you declare your array of pointer-to-member-functions. (Edit: This wasn't what was wrong. I'm keeping this answer up anyway, because typedefs for function pointers can really make code cleaner, so I think this is good advice.)
Try using a typedef:
typedef void (Class::*ftnptr)(JOB Job);
ftnptr[2] fn_ptrs;
Then use it like so:
Class::Class(){
this->fn_ptrs[0] = &Class::ftn1;
this->fn_ptrs[1] = &Class::ftn2;
}
DWORD WINAPI Class::AutoplayerThreadFunction(LPVOID lpParam)
{
Class *pParent = static_cast<Class*>(lpParam);
while(true){
(pParent->*(pParent->fn_ptrs[pParent->m_currentJob.action]))(pParent->m_currentJob);
/* The line above causes the compiler error. Curious to me is that
* neither "pParent->m_currentJob" nor "pParent->m_currentJob" cause
* any problems, although they are members too like the ftnptr array.
*/
}
}
Say I have the following function:
bool foo (int a); // This method declaration can not be changed.
How do I create a pthread for this? And how do I find out what the function returned? I've looked online and it seems like any function I want to create a pthread for must take a void* as an argument, and must return void* as well, and I'm not quite sure how the casting for all this would work, or where I would get the returned bool.
I'm new to C++, so please bear with me =)
As far as you're dealing only with bools (which are, in fact, integers) it's possible, however not recommended, to cast the function to a pthread function type, as a pointer is compatible with (some) integer types:
pthread_t pid;
pthread_create(&pid, NULL, (void *(*)(void *))foo, (void *)argument));
However, you'd better wrap your function into another, pthread-compatible one, then return a pointer to its return value (must be free()'d after use):
void *foo_wrapper(void *arg)
{
int a = *(int *)arg;
bool retval = foo(a);
bool *ret = malloc(sizeof(bool));
*ret = retval;
return ret;
}
then use:
pthread_t pid;
pthread_create(&pid, NULL, foo_wrapper, &a);
With this method, in the future you'll be able to call a function with arbitrary return or argument types.
You could encapsulate the function you want to invoke in a function object, and then invoke that function object from within your pthread function:
First, define a function object that encapsulates your function call.
struct foo_functor {
// Construct the object with your parameters
foo_functor(int a) : ret_(), a_(a) {}
// Invoke your function, capturing any return values.
void operator()() {
ret_ = foo(a_);
}
// Access the return value.
bool result() {
return ret_;
}
private:
bool ret_;
int a_;
};
Second, define a function with the appropriate pthread signature that will invoke your function object.
// The wrapper function to call from pthread. This will in turn call
extern "C" {
void* thread_func(void* arg) {
foo_functor* f = reinterpret_cast<foo_functor*>(arg);
(*f)();
return 0;
}
}
Finally, instantiate your function object, and pass it as a parameter to the thread_func function.
foo_functor func(10);
pthread_t pid;
pthread_create(&pid, NULL, thread_func, &func);
pthread_join(pid, NULL);
bool ret = func.result();
An easy work around is to use void* foo(int a, bool &b).
A bool is functionally equivalent to an int. false is (usually) 0, and true is anything else. Thus
void *foo(void *a){
int *a_int = (int *)a;
//do things
bool *x = new bool;
*x = answer;
pthread_exit(x);
}
Then in your main you would get the returned result by casting it back to a bool.
bool *x;
pthread_join(thread,(void *)x);
//Answer is *x