I would like to forward a callback to a function pointer. So I declare a static (int*) m_pointer1, as well as a method void RegisterCallback1( (int*)fct)
in class1.h:
public:
int RegisterCallback1( int (*fct) );
private:
static int (*m_Callback1);
in class1.cpp:
int class1::RegisterCallback1( int (*fct) )
{
m_Callback1= fct;
}
then, I want to forward the callback to the function pointer:
void class1::Callback1()
{
(*m_Callback1)();
}
But I get a compiler error "Expression must have (pointer-to)- function type
I have followed tutorial and read about function pointers and they seem to do it this way without any problems. Any ideas why?
EDIT:
So, I declare (int*)(void)m_Callback1 -Visual Studio requires a void there...-
Then how do I call the registerCallback function with the argument?
class1.RegisterCallBack1( ??? - class2::callback -??? );
static int (*m_Callback1) does not declate a function pointer, just a pointer to int: you forgot about the parameter list. You meant:
static int (*m_Callback1)();
and
int RegisterCallback1( int (*fct)() );
You haven't declared a function pointer, you've declared a normal data pointer. You are missing () at the end of the declaration.
You can try to limit the missing () errors pointed out by Oli and Dave by using a typedef for the callback function's signature: typedef int (*)() CallBack; This would at least have the merit of letting you think once about the precise number of brackets rather than at every point in your code where you use such a function.
Related
I am trying to create a program which saves the function pointer of a member function to an array. The program then takes the function pointer from that array and calls the function said pointer points to. This works as long as the member function used does not have any arguments. When I give it arguments the following error occurs in Visual Studio 2017:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
My code is:
typedef uint8_t byte;
template<typename T>
class Test
{
public:
void FuncTest(byte* data)
{
cout << (T)(0.0625f) << endl;
}
};
typedef Test<float> fTest;
typedef Test<long long> lTest;
int main()
{
byte data[1024];
{
void (fTest::*ffp)(byte*) = &fTest::FuncTest;
//void (lTest::*lfp)(byte*) = &lTest::FuncTest;
printf("%p\n", ffp);
memcpy(&data[0], (int64*)&ffp, sizeof(int64));
}
{
int64 pData;
memcpy(&pData, &data[0], sizeof(int64));
void(*func_pointer)(byte*) = (void(*) (byte*))(pData);
printf("%p\n", pData);
func_pointer(nullptr);
}
}
If anyone could help, it would be greatly appreciated.
Ignoring the storage in an array your code is essentially:
void (Test::*ffp)(byte*) = &fTest::FuncTest;
void* pData = (void*)ffp;
void(*func_pointer)(byte*) = (void(*) (byte*))(pData);
func_pointer(nullptr);
The type of ffp is essentially (although not exactly due to differing calling conventions) void (fTest*, byte*) which doesn't match the type of func_pointer.
The solution to this is to use std::function with with either std::bind or lambdas to convert the function signatures. e.g.:
std::vector<std::function<void(byte*)>> functions;
fTest test;
functions.push_back([=](byte* data){ test.FuncTest(data); });
functions.front()(nullptr);
I am having difficulty to figure out what is the use typedef here-
typedef char TYPE_SSOSettingError;
typedef void (*ans_executeDomainRegistration) (TYPE_SSOSettingError);
From the first line I understand that TYPE_SSOSettingError is defined as char.
From the next line I can figure out that ans_executeDomainRegistrationis a pointer to a function which is having return type of void and takes parameter of type char which in this situation is TYPE_SSOSettingError
Then what is the use of typedef in the last line?
The typedef is, as you noted, a pointer to a function. So it can be used to declare said pointer to said function and then bind it to an actual pointer to a function with said signature and then called as desired.
typedef char TYPE_SSOSettingError;
typedef void (*ans_executeDomainRegistration) (TYPE_SSOSettingError);
// ...
void somefunc(TYPE_SSOSettingError);
// ...
ans_executeDomainRegistration ptr = &somefunc;
The typical use case for this is with a callback function of some sort. It is used in the standard library for setting the terminate function etc. std::set_terminate, with the terminate handler typedef.
typedef void (*terminate_handler)();
std::terminate_handler set_terminate( std::terminate_handler f );
In more general terms, use of the typedef (and type aliases using) provides a technique to offer a better abstraction.
void (*ptr) (char) = &somefunc; // 1
ans_executeDomainRegistration ptr = &somefunc; // 2
Your case in point, it is unclear in line 1 what ptr will be used for, line 2 offers clearer intent, the ptr will be used as a function call for the execution of a domain registration and that function accepts an SSO settings error.
It is a technique to make the code easier to read, better, terse, or more succinct in order to express the concepts in the code (for some definition of easier, better etc.). Use them well; when not used well, they can also make the code more obscure, and harder to read and understand.
To make more clear declarations like this:
int register_callback(void (*execute) (TYPE_SSOSettingError));
vs
int register_callback(ans_executeDomainRegistration* execute));
Also, to make it clear what a function pointer should be.
You are right this is a typedef of a function pointer with return value void and parameter TYPE_SSOSettingError.
The typedef can be used to increase the readability of your code when
using a function pointer.
Function pointer declarations
For example declaring a function pointer fct_ptr1 and fct_ptr2 which are exactly the same:
// Type definition:
typedef void (*ans_executeDomainRegistration) (TYPE_SSOSettingError);
// Declarations:
ans_executeDomainRegistration fct_ptr1 = foo; // With typedef
void (*fct_ptr2) (TYPE_SSOSettingError) = foo; // Without typedef
Function declarations
Also if you have any function with a function pointer as parameter:
// Write:
void SomeFct(ans_executeDomainRegistration param) {...} // With typedef
// Instead of:
void SomeOtherFct(void (*param)(TYPE_SSOSettingError)) {...} // Without typedef
Conclusion
So as a result of using the typedef you see it is more familiar to
declare pointers or functions if you have declared a type for the function pointer.
typedef void (*ans_executeDomainRegistration) (TYPE_SSOSettingError);
typedefs a function pointer to a function of type void(char).
Example:
void foo(char) {
...
}
int main() {
ans_executeDomainRegistration f = &foo;
f('a');
}
The second typedef makes it so you have a defined type for later use.
Here an example to contrast a use with and without typedef.
#include <stdio.h>
typedef char TYPE_SSOSettingError;
typedef void(*ans_executeDomainRegistration) (TYPE_SSOSettingError);
void myprint(TYPE_SSOSettingError c)
{
printf("%c\n", c);
}
int main()
{
ans_executeDomainRegistration with_typedef = myprint;
void(*without_typedef) (TYPE_SSOSettingError) = myprint;
with_typedef('w');
without_typedef('o');
}
I suppose you've known about typedef, and you're asking about why to use defined typedef at 2nd typedef.
Then what is the use of typedef in the last line.
It's guaranteed that if TYPE_SSOSettingError gets changed, the parameter's type of ans_executeDomainRegistration will get changed too.
Think of a function which returns a function pointer of type ans_executeDomainRegistration.
Imagine something like:
ans_executeDomainRegistration getDomainRegistrationFunction(enum DomainType d)
{
return global_ans_executeDomainRegistration[getDomainindex(d)];
}
which is called like:
(*getDomain(MY_DOMAIN))(varSSOSettingError);
In C++ 11 you can use an alias declaration instead of the typedef that looks more clear.
For example
using ans_executeDomainRegistration = void ( * )( TYPE_SSOSettingError );
From this declaration it is seen that ans_executeDomainRegistration is a name for type void ( * )( TYPE_SSOSettingError ). That is this name denotes the type of pointer to function with one parameter and return type void.
So instead of writing in the program for example like
typedef char TYPE_SSOSettingError;
void myFunc( TYPE_SSOSettingError );
//...
void (*myFuncPtr1) (TYPE_SSOSettingError) = myFunc;
void (*myFuncPtr2) (TYPE_SSOSettingError) = myFunc;
you can write
ans_executeDomainRegistration myFuncPtr1 = myFunc;
ans_executeDomainRegistration myFuncPtr2 = myFunc;
Have a structure:
scheduled_call {
MyClass* object;
int value;
void (MyClass::*setter)(const int)
}
For class:
MyClass {
void doSomething(const int);
}
The structure compiles all well, but when I try to call the value as function, it throws error:
I need to execute call saved in this structure. I tried this:
void executeIt(scheduled_call cl) {
cl.object->*(cl.method)(cl.value);
}
But I get:
error C2064: term does not evaluate to a function taking 1 arguments
My coding is based on C/C++ function pointer guide. I'm doing this as an experiment, if it fails I can fallback to switch statement of course.
Can anybody compile this under Visual Studio 2010?
You need to provide a valid member function pointer definition in your struct:
scheduled_call {
MyClass* object;
int value;
void (MyClass::*method)(int); // <<<<
}
void MyClass::*method;
Is not a valid function pointer to a class memeber function. To get that we need
void (MyClass::*method)(int)
An now method is a pointer to function like MyClass::doSomething()
The problem was in method call. This is wrong:
cl.object->*(cl.method)(cl.value);
This is correct:
(cl.object->*cl.method)(cl.value);
This question already has answers here:
Understanding typedefs for function pointers in C
(8 answers)
Typedef function pointer?
(6 answers)
Closed 9 years ago.
I am reading Linux kernel recently.
I find that in many cases they use the struct "typedef xxx f(xxx)", but I cannot understand how it works. (something like function pointer?)
Here is my test code.
#include<stdio.h>
typedef int Myfunc(int);
typedef int (*point_to_myfunc)(int);
static Myfunc example;
static int example(int a){
printf("example a=%d\n", a);
return 1;
}
static void example2(Myfunc* f){
printf("example2\n");
f(2);
}
static void example3(int (*)(int));
static void example3(int (*point_to_Myfunc)(int)){
printf("example3\n");
point_to_Myfunc(3);
}
int main(){
point_to_myfunc f=&example;
example2(f);
example3(f);
return 0;
}
Can anyone provide a brief explanation for me? Thx~
#include <stdio.h>
typedef int Myfunc(int);
Myfunc is the name of a type; it is a function taking an int argument and returning an int.
typedef int (*point_to_myfunc)(int);
point_to_myfunc is a pointer to a function taking an int argument and returning an int. You could also have: typedef Myfunc *ptr_to_myfunc; if you wished (another name for the same type).
static Myfunc example;
This says 'there exists a function called example of type Myfunc'.
static int example(int a)
{
printf("example a=%d\n", a);
return 1;
}
This is a possible implementation of example. You can't use a typedef name to like Myfunc in the definition of a function of that type.
static void example2(Myfunc *f)
{
printf("example2\n");
f(2);
}
This is a function that takes a pointer to a Myfunc. The line f(2); invokes the function pointed at with the argument 2 and ignores the returned value.
static void example3(int (*)(int));
This declares example3 as a function taking a pointer to a function that takes an int argument and returns an int result. It could have been written as static void example3(point_to_myfunc); or static void example3(ptr_to_myfunc); or static void example3(Myfunc *);.
static void example3(int (*point_to_Myfunc)(int))
{
printf("example3\n");
point_to_Myfunc(3);
}
This is an implementation of example3.
int main(void)
{
point_to_myfunc f = &example;
example2(f);
example3(f);
return 0;
}
This program has a variable f that's a pointer to a function. Interestingly, you could have:
point_to_myfunc f2 = example;
point_to_myfunc f3 = *example;
Etc. And they all mean the same thing.
You could also invoke them using:
(*f2)(101);
(**f3)(103);
The standard notation for the initialization would use neither the & nor the *. If you're an old school C programmer, you may well invoke the function pointer using the (*f2)(101) notation; before the C89 standard, that was the only way to invoke function pointers. Modern style tends to be f2(101); instead.
Vaughn Cato is correct,
In addition,
typedef int (*point_to_myfunc)(int);
defines a function pointer, it means point_to_myfunc is a type,we can use it like this:
point_to_myfunc f=&example;
now f is just like example(), we could f() to call method example
typedef int Myfunc(int);
This means that Myfunc is the type of a function which takes an int parameter and returns an int.
This line:
static Myfunc example;
is the same as saying
static int example(int);
which forward-declares the example function.
One use for this would be to make it clearer that a particular set of functions are used for a particular purpose.
typedef char CharacterConverter(char);
extern CharacterConverter make_upper_case;
extern CharacterConverter make_lower_case;
extern void process_string(char *s,CharacterConverter *f);
// easier to see that make_upper_case and make_lower_case are valid arguments.
typedef is useful when define a type.
For example:
char *a, b; defined a pointer "a", and a char b.
char *a, *b defined two char pointers.
If use typedef, it will be clear:
typedef char* PCHAR;
PCHAR a,b;
Now, both a and b is a char pointer.
typedef int Myfunc(int);
typedef int (*point_to_myfunc)(int);
the two lines defined a pair, a function format and a type of pointer which can point to the function, so it will be clear and more obvious when using them.
In a C lib, there is a function waiting a function pointer such that:
lasvm_kcache_t* lasvm_kcache_create(lasvm_kernel_t kernelfunc, void *closure)
where lasvm_kernel_t is defined as:
typedef double (*lasvm_kernel_t)(int i, int j, void* closure);
Now, if I send a method defined in a class to lasvm_kcache_create:
double cls_lasvm::kernel(int i, int j, void *kparam)
...
lasvm_kcache_t *kcache=lasvm_kcache_create(&kernel, NULL);
I get: "cannot convert ‘double (cls_lasvm::)(int, int, void)’ to ‘double ()(int, int, void)’"
What should I do?
I'm assuming that the closure argument is a context 'cookie' for the use of the callback to get appropriate context. This is a acomon idiom for callback functions, and seems to be what's going on based on the snippets you've provided (but I don't know for sure, as I don't know anything about kcache_create() except what you posted here).
You can use that cookie to pass a pointer to the cls_lasvm instance you're dealing with like so:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// have to get a cls_lasvm pointer somehow, maybe the
// void* clpsure is a context value that can hold the
// this pointer - I don't know
cls_lasvm* me = reinterpret_cast<cls_lasvm*>( closure);
return me->kernel( i, j)
}
class cls_lasvm //...
{
...
// the callback that's in the class doens't need kparam
double cls_lasvm::kernel(int i, int j);
};
...
// called like so, assuming it's being called from a cls_lasvm
// member function
lasvm_kcache_t *kcache=lasvm_kcache_create(&lasvm_kcache_create_callback, this);
If I'm wrong about closure being a context cookie, then your callback function in the cls_lasvm class needs to be static:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// if there is no context provided (or needed) then
// all you need is a static function in cls_lasvm
return cls_lasvm::kernel( i, j, closure);
}
// the callback that's in the class needs to be static
static double cls_lasvm::kernel(int i, int j, void* closure);
Note that a C callback function implemented in C++ must be extern "C". It may seem to work as a static function in a class because class-static functions often use the same calling convention as a C function. However, doing that is a bug waiting to happen (see comments below), so please don't - go through an extern "C" wrapper instead.
If closure isn't a context cookie and for some reason cls_lasvm::kernel() can't be static then you need to come up with a way to stash a this pointer somewhere and retrieve that pointer in the lasvm_kcache_create_callback() function, similar to the way I did in my first example, except that pointer has to come dfrom some mechanism you devise yourself. Note that this will likely make using lasvm_kcache_create() non-reentrant and non-threadsafe. That may or may not be a problem depending on your specific circumstances.
Every C++ member function has an implicit, hidden, first parameter, this.
So the method double cls_lasvm::kernel(int i, int j, void* kparam) is really:
double cls_lasvm::kernel(cls_lasvm* this, int i, int j, void* kparam), and it is inappropriate/impossible to use it as a function-pointer parameter.
To make progress, convert your method to be a static-member-method. That will remove the this pointer. You may still have other issues to overcome, but that is a good start.
If it is an external C library whose code you can not modify, then there is not much you can do about it. You'll not be able to call the member function as they require this pointer to work properly (to get the attributes of the object). The easiest workaround, I can think of is using third void* param to pass around this pointer. You can define struct like after defining one more typedef like:
typedef double (cls_lasvm::*lasvm_kernel_t_member)(int i, int j, void* closure);
struct MyParam
{
A* pThis;
lasvm_kernel_t_member pMemFun;
void* kParam;
};
I haven't compiled it, I hope it makes sense.
Then in your class define a static method which receives the call from library:
class cls_lasvm
{
static double test(int i, int j, void *kparam)
{
MyParam* pParam = reinterpret_cast<MyParam*>(kparam);
return (pParam->*pMemFun)(i,j,pParam->kParam);
}
};
While calling you should use something like:
cls_lasvm a;
MyParam param;
param.pThis = &a;
param.pMemFun = &cls_lasvm::kernel;
param.kParam = NULL;
lasvm_kcache_create(&cls_lasvm::test,&a);