Callback function as an argument --- where's its argument?

So I'm porting this C++ program to LabVIEW. I'm a total newbie on Callbacks, and it uses a lot of them (the program gets information from an haptics hardware).

In the original program, there is a function defined as
1
2
3
4
5
HDCallbackCode HDCALLBACK updateDeviceCallback(void *pUserData)
{   
...blah blah blah...
 return HD_CALLBACK_CONTINUE;    
}


The header defines

1
2
3
4
5
/* Return code for callbacks, determines whether the operation is finished
   and will unscheduled, or whether it will continue running. */
typedef unsigned int HDCallbackCode;
#define HD_CALLBACK_DONE     0
#define HD_CALLBACK_CONTINUE 1 


So I ported this function to LabVIEW telling it that the return type is an integer.

But then I need to call it as an argument for another function: in the main loop there is this instruction:


1
2
hUpdateHandle = hdScheduleAsynchronous(
        updateDeviceCallback, 0, HD_MAX_SCHEDULER_PRIORITY);


The API reference defines
1
2
3
4
HDSchedulerHandle
hdScheduleAsynchronous(HDSchedulerCallback pCallback,
void *pUserData,
HDushort nPriority)



Helios helped me to see that HDSchedulerCallback is a pointer. (http://www.cplusplus.com/forum/beginner/11576/)


So I don't get it.
1) hdScheduleAsynchronous() expects a HDSchedulerCallback, i.e. a pointer, but the main program is feeding an int function.
2) What's the argument of updateDeviceCallback()? It expects a pointer to void data, but where is it coming from?

I'm sure I'm missing some important concept about Callbacks. From this website I learned perfectly about pointers, but found nothing about callbacks. All I know now is what wikipedia taught me, which is not much. And I'm also getting some help from here:
http://brl.ee.washington.edu/Education/EE589/AIIT/NotesPack/OmniProgramming1.pdf

which turns out to work with the exact same program I'm trying to port to LabVIEW.

but the main program is feeding an int function.

I don't know what you mean by that.

A callback is a function that you write but that you don't call yourself. Instead you register it with the system and the system calls it for particular events.

You must write a callback function with a given signature. Suppose it takes a void* and returns an int, then it will look something like the function below. (The define macro CALLBACK represents the possibility of a different calling convention for callback functions.)

1
2
3
4
int CALLBACK myCallback( void* data )
{
    // ...
}


Then the system is told of its existence so that it can be called:

1
2
RegisterCallback( myCallback, 0 );
// Now the system will call myCallback with a null pointer arg. 


The void* is just so you can pass arbitrary data to it. You could pass an integer (just cast the int to a void*) or you could pass a pointer to arbitrary data.

1
2
3
4
5
6
7
8
struct CallbackData {
    // ...
};

CallbackData* data = new CallbackData( ... );

RegisterCallback( myCallback, (void*)data );
// Now the system will call myCallback with the CallbackData struct. 

Last edited on
I didn't say it was a pointer. I said it was a pointer to a function.
1) hdScheduleAsynchronous() expects a HDSchedulerCallback, i.e. a pointer, but the main program is feeding an int function.


A global function name without its parenthesis is a pointer to that function, much like an array without brakets is a pointer to the array. Alternatively, you can throw a & before the function name for clarity (I prefer to do this, as it's a requirement in C++ member function pointers anyway -- and it just makes more sense). Therefore an alternative way to call hdScheduleAsynchronous would be:

1
2
3
hUpdateHandle = hdScheduleAsynchronous(
        &updateDeviceCallback,                    //  <-- notice & here
        0, HD_MAX_SCHEDULER_PRIORITY);


It will work with or without the & though. Leaving out the & is kind of a shortcut. Personally I find it sloppy that C/C++ lets you leave it out for global functions, but oh well.

2) What's the argument of updateDeviceCallback()? It expects a pointer to void data, but where is it coming from?


In all likelyhood this is the 'pUserData' value you pass to hdScheduleAsynchronous. Callbacks often have a "user data" argument that you supply so that you can objectify them somewhat. IE, you could pass a pointer to a specific object as pUserData, and you'd get a pointer to that object as the parameter when the callback is called, so you can access the object without having to rely on globals or stuff like that. This is pretty standard among C-style callbacks.


If you want to learn more about C/C++ function pointers, here's a site with great walkthroughs and tutorials:

http://www.newty.de/fpt/index.html


EDIT -- blah I'm so slow XD
Last edited on
Thank you all!
It's pretty clear now... kind of.

Now I need to head to some LabVIEW forum 'cause I have NO idea how to implement these callbacks inLabVIEW

Thanks for the help!
Topic archived. No new replies allowed.