Using callbacks in C++ - c++

I'm working on a project in C++, but at some point in the application it fails and generates a core dump. The application uses a couple of classes, which for the purposes here I'm concentrating on one of the classes, which I'm calling A, and is instantiated as object a. This has a large number of member functions, of which at the moment only a few are being used, but one of these generates a log to produce diagnostics to be used for debugging. I want to use this to find out why the application is failing.
The project is to put together code that invokes the various member functions, and although I have access to the source code and some limited documentation, none of the code can be changed, with all changes being in the code that makes use of the classes and invokes the member functions. The member function in question is:
void enable_log (log_callback callback, void * user_data = nullptr)
where the 1st argument callback contains the message and 2nd argument is optional. For now it can be set to nullptr, so would be invoked as:
a.enable_log(callback, nullptr);
From this documentation it's not at all clear what exactly callback is. However, in looking at the source code this is:
using log_callback = void (*)(const std::string& message, void* user_data);
in a header file, where log_callback is an alias for const std::string& if I understand this correctly.
I already have dummy classes on a platform using Visual Studio 2019 with some test member functions to simulate invoking the member functions on a remote Linux server, but I'm unable to find a way of making use of the member function above. I added the test member function to the dummy class as follows:
void enable_log(const std::string& callback, void* user_data = nullptr) {
callback = "ABCD";
}
which is supposed to generate a test string which is returned, such that in the real application this string will have diagnostic information that will be written to a file. However, the "=" is an error.
The idea is that in the main function an empty string will be declared, then enable_log() should populate this string, which can be printed out.
I've spent some time looking at various resources, including Stackoverflow, but I cannot find a way of returning a string with the information that can be printed out. I need a simple way to simulate this, and as I said above, I must not change the source code of the real member function, so the simulated member function has to produce a string in the same way. How is this done? Some advice would be appreciated.

Callback, in simple words, is some function that will be called later at some point. Example:
void callback_fn(int a);
using callback_t = (void)(*)(int a);
void some_func(callback_t);
You can use some_func() like so:
some_func(callback_fn);
Full example here: https://godbolt.org/z/ET3GhfYrv
For your usecase the parameters of the callback are slightly different. Here's how to read the syntax:
using log_callback = // this just creates an alias for whatever is on the right handside
void // the return type of the "callable" should be void
(*) // this tells us that it is a function pointer
(const std::string& message, void* user_data) // These are the arguments the callable takes. It is a "std::string" and a "void *"
To use this, just create a free function with the same signature:
void callable(const std::string &msg, void *userData = nullptr)
{
// msg is the data sent by the function. use it in whatever way
// you want.
std::cout << msg << '\n';
}
// Pass it to the enable_log
enable_log(callable);

Related

Pointer problem using functions from non-object API in objects

I am writing some C++ code to get data from a SDR (software defined radio) and analyse it using an FFT library (FFTW3). The software uses an API (SDR_play_API and its DLL). I am trying to include the API functionality into an object. The library comes with a non-object based example program.
The IDE I am using is VS2105.
Three of the functions are callbacks to handle events from the hardware. The address of the callback functions that handle these events are passed to the API through a structure. I include the relevant code snippets from the example program, the header files and my own code after a description of the problem.
Though I have been on some C++ training - and taught others the basics - I am far from an expert and the problem goes beyond my understanding of pointers and objects.
The problem I have is one that has been discussed before on Stack Exchange. It is a problem of pointers to member functions.
The simple solution would seem to be to make the functions STATICs. However that causes problems because of some of the variables used in these functions. Without making them static then the compiler complains and if I make them static the linker complains because there is no matching definition for static variables in the library.
I have looked through Stack Exchange tried the solutions suggested but I can't seem to make any of them work - I get compiler errors.
So I feel ideally I just want to pass the pointers to the member functions to API through the structure ... but I have tried all sorts of variations on syntax without success. Can anyone help?
The API comes with an example program that does not use objects. So before I reveal my attempts to use the functions in an object, here is the code from the example program. First I will show where it assigns the location of the functions to the members of the structure, then I will include the structure definitions etc from the header file.
First then, the assignment:
// Assign callback functions to be passed to sdrplay_api_Init()
cbFns.StreamACbFn = StreamACallback;
cbFns.StreamBCbFn = StreamBCallback;
cbFns.EventCbFn = EventCallback;
Here, from the header file that comes with the API, is the definition of the structure
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
and here, again from the header file that comes with the API is the definition of the data types - you can see the these are function pointers
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
here is one of the call back function declarations
void StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
...
}
So that all works fine and compiles - but it that works in a non-object scenario.
However when I make the functions a member of a class then I get errors. I have tried the following variations without success. Can someone please point me in the right direction - if I had had hair by now I wouldn't have anymore cause it would be on the floor all around me in clumps.
function definition:
void sdr_object::StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
...
}
Unsuccessful attempts to assign to structure include (including compiler error)
cbFns.StreamACbFn = this->StreamACallback;//"non standard syntax: use '&' to create a pointer to the member"
//cannot convert from 'void (__cdecl sre_object::*)(...) to sdrplay_api_StreanCallback_t
cbFns.StreamACbFn = &this->StreamACallback;//'&': illegal operation on bound member function experssion
cbFns.StreamACbFn = this->sdr_object::StreamACallback; //"non standard syntax: use '&' to create a pointer to the member"
//cannot convert from 'void (__cdecl sre_object::*)(...) to sdrplay_api_StreanCallback_t
cbFns.StreamACbFn = &this->sdr_object::StreamACallback; //'&': illegal operation on bound member function experssion
Any wisdom will e received most gratefully. (How to do it will be received even more gratefully ...!)
This answer comes with many thanks to Igor Tandetnik who suggested the solution in comments above.
Igor wrote "Make your callbacks static member functions. Pass this pointer for cbContext parameter to sdrplay_api_Init - you get that same pointer back in the callback. Now the callback can do static_cast<MyClass*>(cbContext)->memberFunction(params); . The actual logic can now be implemented in a non-static member function; the static one just serves as a glue between C++ implementation and C API"
My implementation of that is as follows:
Add to the class declaration in the header file an intermediary "glue" function for each event handler e.g.:
static void sdr_object::StreamACallback_static(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
static_cast<sdr_object*>(cbContext)->StreamACallback(xi, xq, params, numSamples, reset, cbContext);
};
For the function above, the pointer that is handed to the API then becomes
cbFns.StreamACbFn = this->StreamACallback_static;
In my particular example, I then had to do the same for the other two functions.
I did not have to change any other existing code.
Again, many thanks to Igor for the answer - I hope I have implemented it as he intended ... that said, what I have described works, so I imagine I have!

Passing arbitrary data to a C++ callback that doesn't accept a "void* userarg"

EDIT:
I have modified the example API so it better reflects the real API I am dealing with. The way the API get's the message argument passed to it is by user input so the message argument cannot be used to pass additional data.
I am dealing with a very frustrating API that uses callback routines that don't take "void* userarg" pointers.
Assuming the function that uses the callback routine as defined by the API expects a string argument (that will be assigned by user input), is there ANY possible way to get more data into my callback routine without using global variables?
Here is a simplified example of what the API might look like:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// ASSUME EVERYTHING IN THIS SECTION IS PART OF AN API AND IS NOT MY OWN CODE...
// I DO NOT HAVE THE SOURCE AND IT CANNOT BE MODIFIED
typedef void (*CALLBACK)(string message);
void call_callback(CALLBACK cb) {
// Gets a message from user input
string message = "hello"; // pretend this is user input
cb(message);
}
////////////////////////////////////////////////////////////////////////////////
int data = 42;
void callback_function(string message) {
// I want to access "data" here WITHOUT it being global
cout << message << ' ' << data << endl;
}
int main(int argc, char** argv) {
call_callback(&callback_function);
}
Typically an API that uses callbacks would also pass a "void* userarg" argument into the callback routine so you could pass additional data of any type, but that is not the case here.
This API is used extensively throughout our whole codebase and it is 100% necessary to pass a lot more data in every case where it is used. The current way we get more data in *prepare to cringe* is by storing practically all of our data in singletons so nearly everything is global and can be accessed from literally anywhere in the program.
This whole concept seems EVIL to me, but without a better API I can't figure out any better way to get the data into the callback. I have already contacted the vendor and asked that they fix their API to make it accept a "void* userarg" argument, but it doesn't look like it will be fixed anytime in the near future...
All I am hoping for is ANY better way of doing things than we are now.
If it is really an std::string which is an argument to the callback (and not something else) and you really have access to the argument (as in your sample code which invokes call_callback with supplied string) you can put an entity-serialized pointer to your allocated object into std::string (which is allowed to have arbitrary data in it) and invoke call_callback with it.
One challenge here would be the fact that you'd than have to manually manage this pointer.
My most straightforward idea would be to provide unique strings in place of the void* you would normally expect. You'd then have one map singleton that maps the strings to your callbacks.
So something like this:
class Dispatcher
{
public:
// TODO: Thread safety etc.
std::string makeCallback(std::function<void()> callback)
{
std::string uid = std::to_string(_index);
_callbacks[uid] = std::move(callback);
_index++;
return uid;
}
void runCallback(std::string uid)
{
_callbacks[uid]();
}
private:
size_t _index = 0;
std::map<std::string, std::function<void()>> _callbacks;
};
void leaveAPI(std::string uid)
{
getSingleton<Dispatcher>()->runCallback(uid);
}
void enterAPI(std::function<void()> userCallback)
{
std::string uid = getSingleton<Dispatcher>()->makeCallback(userCallback);
call_callback(leaveAPI, uid);
}
Demo
You just count up a number every time you call the API and use its string version as the callback parameter. The class also maps each of those strings to the callback you wanted called. You could remove the map entries or do any number of performance optimizations, but this is the gist of it.
(This would work just as well with const char* if you figure out the ownership/lifetime questions that it opens.)
You should really petition the writers of the API to use std::function instead of raw pointers to functions.
Then you can easily use e.g. std::bind or lambda expressions to be able to call functions taking more arguments than the callback takes.
For example:
// The callback is a function taking one string argument, and return nothing
using CALLBACK = std::function<void(std::string)>;
// Do some processing and then call the callback function
void call_callback(CALLBACK cb, std::string message)
{
// ...
cb(message);
}
// Our callback takes a string *and* an integer argument
void callback_function(std::string message, int data)
{
std::cout << message << ' ' << data << '\n';
}
int main()
{
int local_data = 42;
// Using std::bind...
using namespace std::placeholders; // for _1, _2, _3...
call_callback(std::bind(&callback_function, _1, local_data), "Foobar");
// Using lambdas...
call_callback([local_data](std::string message)
{
callback_function(message, local_data);
}, "Foobar");
}
Using std::function also makes it easy to use member functions as callbacks as well, not only non-member functions (or static member functions).
However, if you can't modify the API, or the creator of it won't change it and it have to use C-style plain pointers to non-member functions, you can still solve it with lambdas, but you can't have any captures for the lambda:
call_callback([/*empty!*/](std::string message)
{
// Call the function as defined in the previous snippet
callback_function(message, 42); // Pass the value directly
}, "Foobar");

How to make a function that returns the name of the argument passed

I am looking for a way to create a naming service. Basically I need a function that accepts anything as an argument and returns me the name of the given argument. This can be anything, class, function, variable etc.
std::string name(T t)
{
if t is a function
return __func__ of t
if t is a variable
return name of variable.
}
Any suggestions?
C++ is not the right language to do this, it has no reflection capabilities at all, and you can't treat "anything, class, function, variable etc." uniformly. You can't pass a class to a function, or pass a function to a function, they are not objects.
With MACRO, you may do
#define name(n) #n
which stringify given argument.
In C++ the name of a function or of a variable is just non sense. The name is only known at build time (compile & link) and later translated to an address. At run time all names have just vanished and cannot be knows - except when using special build mode to allow debuggers to keep track of original names.
What would be closer than that would be a function accepting a pointer to void:
std::string address(const void *t) {
std::ostringstream os;
os << "Address is " << t;
return os.str();
}
You can then use it this way:
int i;
std::string s;
s = address(static_cast<const void *>(&i));
...
double d;
s = address(static_cast<const void *>(&d));
...
// if f is declared as int f(double d, std::string s):
s = address(static_cast<const void *>(&f));
As answered already, C++ doesn't have reflection. But if you have debug symbols available at runtime different OS/compiler combinations make that information available - if you put enough effort into it.
Search for mechanisms to get the C++ stack trace or back trace.
E.g., this question has multiple answers that point to libraries that are useful for Linux, and separately for Windows: C++ display stack trace on exception (There are also other answers on SO and on the web in general.)

Bad practice to call static function from external file via function pointer?

Consider the following code:
file_1.hpp:
typedef void (*func_ptr)(void);
func_ptr file1_get_function(void);
file1.cpp:
// file_1.cpp
#include "file_1.hpp"
static void some_func(void)
{
do_stuff();
}
func_ptr file1_get_function(void)
{
return some_func;
}
file2.cpp
#include "file1.hpp"
void file2_func(void)
{
func_ptr function_pointer_to_file1 = file1_get_function();
function_pointer_to_file1();
}
While I believe the above example is technically possible - to call a function with internal linkage only via a function pointer, is it bad practice to do so? Could there be some funky compiler optimizations that take place (auto inline, for instance) that would make this situation problematic?
There's no problem, this is fine. In fact , IMHO, it is a good practice which lets your function be called without polluting the space of externally visible symbols.
It would also be appropriate to use this technique in the context of a function lookup table, e.g. a calculator which passes in a string representing an operator name, and expects back a function pointer to the function for doing that operation.
The compiler/linker isn't allowed to make optimizations which break correct code and this is correct code.
Historical note: back in C89, externally visible symbols had to be unique on the first 6 characters; this was relaxed in C99 and also commonly by compiler extension.
In order for this to work, you have to expose some portion of it as external and that's the clue most compilers will need.
Is there a chance that there's a broken compiler out there that will make mincemeat of this strange practice because they didn't foresee someone doing it? I can't answer that.
I can only think of false reasons to want to do this though: Finger print hiding, which fails because you have to expose it in the function pointer decl, unless you are planning to cast your way around things, in which case the question is "how badly is this going to hurt".
The other reason would be facading callbacks - you have some super-sensitive static local function in module m and you now want to expose the functionality in another module for callback purposes, but you want to audit that so you want a facade:
static void voodoo_function() {
}
fnptr get_voodoo_function(const char* file, int line) {
// you tagged the question as C++, so C++ io it is.
std::cout << "requested voodoo function from " << file << ":" << line << "\n";
return voodoo_function;
}
...
// question tagged as c++, so I'm using c++ syntax
auto* fn = get_voodoo_function(__FILE__, __LINE__);
but that's not really helping much, you really want a wrapper around execution of the function.
At the end of the day, there is a much simpler way to expose a function pointer. Provide an accessor function.
static void voodoo_function() {}
void do_voodoo_function() {
// provide external access to voodoo
voodoo_function();
}
Because here you provide the compiler with an optimization opportunity - when you link, if you specify whole program optimization, it can detect that this is a facade that it can eliminate, because you let it worry about function pointers.
But is there a really compelling reason not just to remove the static from infront of voodoo_function other than not exposing the internal name for it? And if so, why is the internal name so precious that you would go to these lengths to hide that?
static void ban_account_if_user_is_ugly() {
...;
}
fnptr do_that_thing() {
ban_account_if_user_is_ugly();
}
vs
void do_that_thing() { // ban account if user is ugly
...
}
--- EDIT ---
Conversion. Your function pointer is int(*)(int) but your static function is unsigned int(*)(unsigned int) and you don't want to have to cast it.
Again: Just providing a facade function would solve the problem, and it will transform into a function pointer later. Converting it to a function pointer by hand can only be a stumbling block for the compiler's whole program optimization.
But if you're casting, lets consider this:
// v1
fnptr get_fn_ptr() {
// brute force cast because otherwise it's 'hassle'
return (fnptr)(static_fn);
}
int facade_fn(int i) {
auto ui = static_cast<unsigned int>(i);
auto result = static_fn(ui);
return static_cast<int>(result);
}
Ok unsigned to signed, not a big deal. And then someone comes along and changes what fnptr needs to be to void(int, float);. One of the above becomes a weird runtime crash and one becomes a compile error.

callback functions and static_cast for wrapping class methods

I'm having some trouble making a callback wrapper class method that needs to be used by a third party library; the JackAudio library.
I have been able to make a wrapper for a JackAudio callback function that needs two arguments.
I'm just having trouble creating a callback function for a particular function that needs a const char * as an argument.
So far I have been able to make the JackAudio library jack_set_sample_rate_callback function use a custom class and can be executed like so:
SoundClass Sound;
SoundClass * SoundPointer = &Sound;
jack_set_sample_rate_callback(
client,
SoundClass::SampleRateCallbackWrapper,
SoundPointer
);
And the class looks something like this:
SoundClass
{
int SampleRateCallback( jack_nframes_t nframes )
{
//executes some code when called.
}
static int SampleRateCallbackWrapper( jack_nframes_t nframes, void * arg )
{
return static_cast < SoundClass* > ( arg )->SampleRateCallback( nframes );
}
};
All of the above works well, with no issues.
The problem I'm having now is with the JackAudio callback function jack_set_error_function
This is what I tried:
static void ErrorCallbackWrapper( const char * arg )
{
return static_cast < SoundClass*>( arg )->SomeErrorFunction();
}
But I get error: invalid static_cast from type ‘const char*’ to type ‘SoundClass*’
I get the gist why this is happening, I just have no idea what to do for a solution.
Thanks in advance for any help guys.
Assuming the Jack API is written for the C language, there is a formal problem already with the working callback that you have. Namely that it then needs to be extern "C", and that as a static member function it cannot be. So formally it needs to be a free-standing function.
The documentation that you link to for the jack_set_error_function gives this signature, presumably expressed in C:
void jack_set_error_function( void(*)(const char *) func);
For C++ the callback must be assumed to be extern "C", so,
extern "C" void MyErrorFunction( char const* errorMessage )
{
// Whatever, e.g. post a message to the GUI event queue, or terminate.
}
If you want this function to in turn call a method on an object, then unless the library provides some special mechanism to help you, you will just have to use one of the following techniques:
a namespace scope variable accessed by the callback, or
a dynamically generated callback.
C++ does not as of yet support the second approach, at all, so the first one is strongly indicated – if you want a callback on a method of an object.
EDIT: Sorry, I forgot to mention,
the function declarations in the API documentation are syntactically invalid.
E.g. the documentation’s signature
void jack_set_info_function( void(*)(const char *) func );
simply won’t compile with a standard-conforming compiler. Not as C, and not as C++. It’s syntactically invalid in both languages.
Instead it should be
void jack_set_info_function( void(*func)(const char *) );
Since the documentation apparently is generated by DOxygen, it stands to reason that it's been generated from source code that compiles. If so then this is a bug in DOxygen, and a problem with the quality assurance of the library provider. However it might be a problem that lies solely with the library provider, or, I might be mistaken in the assumption that this is a C library?