The code below is running correctly with any online gcc compiler I found (gcc 9.2.0), it also run correctly with CYGWIN gcc compiler, but unfortunately it doesn't work well with MINGW gcc compiler - looks like it passes invalid parameter as "this" to "methodA" and "methodB" methods, when they are called, instead of expected results (56,58) i get some random high numbers.
#include <iostream>
using namespace std;
class CallbackBase
{
public:
using METHOD_TYPE = int (CallbackBase::*)(...);
};
class CallbackProvider : public CallbackBase
{
public:
int methodA(int a,int b,int c)
{
return a+b+c+d;
}
int methodB(double a,double b,double c)
{
return a+b+c+d;
}
private:
int d=8;
};
class CallbackRunner
{
public:
CallbackBase::METHOD_TYPE m_method;
CallbackBase* m_this;
void install (CallbackBase* _this, CallbackBase::METHOD_TYPE _method)
{
m_method =_method;
m_this =_this;
}
int Run1()
{
return (m_this->*m_method)(15L,16L,17L);
}
int Run2()
{
return (m_this->*m_method)(15.6,16.7,17.8);
}
};
int main()
{
CallbackProvider cp;
CallbackRunner cr;
cr.install(&cp,(CallbackBase::METHOD_TYPE)&CallbackProvider::methodA);
cout << "result " << cr.Run1() << endl;
cr.install(&cp,(CallbackBase::METHOD_TYPE)&CallbackProvider::methodB);
cout << "result " << cr.Run2() << endl;
return 0;
}
The problem is solved if I add __cdecl attribute to this methods:
int __cdecl methodA(int a,int b,int c)
int __cdecl methodB(double a,double b,double c)
I doesn't use -mrtd compilation flag.
According to this, __cdecl should be a default calling convention for gcc compilers but looks like it doesn't the case for MINGW.
Is that possible to set __cdecl as a default calling convention for my project?
or as alternative, is there a way to set "default" attribute to all the methods?
I am using Windows 10 with 64 bit architecture.
You're not allowed to use a pointer to function with a C-style variadic parameter to call functions with regular parameters. There's a reason your cr.install calls don't work without a pointer cast.
The simplest solution is to cast the callback pointer to the proper type before calling it, based on the arguments you want to call it with. You can write a template that will do the cast for you.
However, this is highly unsafe, since it's easy to cast to an incorrect type. (Your code would be equally unsafe, if it wasn't undefined to begin with.)
A safer approach is to store the function pointer in a std::any. Then, attempting a callback call with invalid parameters will cause a runtime error (that is, std::any_cast will detect parameter type mistmatch).
Your code has a bug - it has undefined behavior. The cast from int (Class::*)(int, int, int) to int (CallbackBase::*)(...) triggers it. Those two types are not the same, and you can not cast between them willy-nilly.
This is an extract of your code where you are attempting this illegal cast:
cr.install(&cp,(CallbackBase::METHOD_TYPE)&CallbackProvider::methodA);
You can easily see the diagnostic message yourself if you remove the cast:
error: cannot convert 'int (CallbackProvider::*)(int, int, int)' to 'CallbackBase::METHOD_TYPE' {aka 'int (CallbackBase::*)(...)'}
The fact that it works on some compilers and not on the others is of no significance, it is just a manifestation of undefined behavior.
You could cast back to the original function type before calling it, but than the whole thing would become even more ugly.
Another option might be to make your concrete functions variadic as well, and access parameters via VA_ARGS. This would throw the whole C++ type safety off the window, and I do not like this approach either.
Just for the trivia, it looks like mingw's gcc uses a legacy calling convention (cdecl is indeed quite legacy) for variadic functions, while other compilers would use modern AMD ABI.
Related
I'm getting a compile error (MS VS 2008) that I just don't understand. After messing with it for many hours, it's all blurry and I feel like there's something very obvious (and very stupid) that I'm missing. Here's the essential code:
typedef int (C::*PFN)(int);
struct MAP_ENTRY
{
int id;
PFN pfn;
};
class C
{
...
int Dispatch(int, int);
MAP_ENTRY *pMap;
...
};
int C::Dispatch(int id, int val)
{
for (MAP_ENTRY *p = pMap; p->id != 0; ++p)
{
if (p->id == id)
return p->pfn(val); // <--- error here
}
return 0;
}
The compiler claims at the arrow that the "term does not evaluate to a function taking 1 argument". Why not? PFN is prototyped as a function taking one argument, and MAP_ENTRY.pfn is a PFN. What am I missing here?
p->pfn is a pointer of pointer-to-member-function type. In order to call a function through such a pointer you need to use either operator ->* or operator .* and supply an object of type C as the left operand. You didn't.
I don't know which object of type C is supposed to be used here - only you know that - but in your example it could be *this. In that case the call might look as follows
(this->*p->pfn)(val)
In order to make it look a bit less convoluted, you can introduce an intermediate variable
PFN pfn = p->pfn;
(this->*pfn)(val);
Try
return (this->*p->pfn)(val);
Just to chime in with my own experience, I've come across an error in g++ caused by this statement:
(this -> *stateHandler)() ;
Where stateHandler is a pointer to a void member function of the class referenced by *this. The problem was caused by the spaces between the arrow operator. The following snippet compiles fine:
(this->*stateHandler)() ;
I'm using g++ (GCC) 4.4.2 20090825 (prerelease). FWIW.
p->pfn is a function pointer. You need to use * to make it function. Change to
(*(p->pfn))(val)
I'm trying to get function addresses which are hidden behind structures. Unfortunately, the void* basic C++ conversion doesn't work, so I used C++ template instead.
1. Basic void* C++ conversion doesn't work with functions inside structures, why?
void * lpfunction;
lpfunction = scanf; //OK
lpfunction = MessageBoxA; //OK
I made a simple structure :
struct FOO{
void PRINT(void){printf("bla bla bla");}
void SETA(int){} //nothing you can see
void SETB(int){} //nothing you can see
int GETA(void){} //nothing you can see
int GETB(void){} //nothing you can see
};
///////////////////////////////////////////
void *lpFunction = FOO::PRINT;
And the compiling error :
error C2440: 'initializing' :
cannot convert from 'void (__thiscall FOO::*)(void)' to 'void *'
2. Is getting function member addresses impossible?
Then, I made a template function which is able to convert a function member to address. Then I will call it by assembly. It should be something like this:
template <class F,void (F::*Function)()>
void * GetFunctionAddress() {
union ADDRESS
{
void (F::*func)();
void * lpdata;
}address_data;
address_data.func = Function;
return address_data.lpdata; //Address found!!!
}
And here is the code :
int main()
{
void * address = GetFunctionAddress<FOO,&FOO::PRINT>();
FOO number;
number.PRINT(); //Template call
void * lpdata = &number;
__asm mov ecx, lpdata //Attach "number" structure address
__asm call address //Call FOO::PRINT with assembly using __thiscall
printf("Done.\n");
system("pause");
return 0;
}
But, I see it is extremely specific. It looks like LOCK - KEY, and I have to make a new template for every set of argument types.
Original (OK) :
void PRINT(); //void FOO::PRINT();
Modify a bit :
void PRINT(int); //void FOO::PRINT(int);
Immediately with old template code the compiler shows :
//void (F::*func)();
//address_data.func = Function;
error C2440: '=' : cannot convert from
'void (__thiscall FOO::*)(int)' to 'void (__thiscall FOO::*)(void)'
Why? They are only addresses.
69: address_data.func = Function;
00420328 mov dword ptr [ebp-4],offset #ILT+2940(FOO::PRINT) (00401b81)
...
EDIT3 : I know the better solution :
void(NUMBER::*address_PRINT)(void) = FOO::PRINT;
int(NUMBER::*address_GETA)(void) = FOO::GETA;
int(NUMBER::*address_GETB)(void) = FOO::GETB;
void(NUMBER::*address_SETA)(int) = FOO::SETA;
void(NUMBER::*address_SETA)(int) = FOO::SETB;
It's much better than template. And by the way I want to achieve the goal :
<special_definition> lpfunction;
lpfunction = FOO::PRINT; //OK
lpfunction = FOO::GETA; //OK
lpfunction = FOO::GETB; //OK
lpfunction = FOO::SETA; //OK
lpfunction = FOO::SETB; //OK
Is this possible?
Pointers to member functions are nothing like pointers to global functions or static member functions. There are many reasons for this, but I'm not sure how much you know about how C++ works, and so I'm not sure what reasons will make sense.
I do know that what you are trying in assembly simply won't work in the general case. It seems like you have a fundamental misunderstanding about the purpose of member functions and function pointers.
The thing is, you are doing some things that you would generally not do in C++. You don't generally build up tables of function pointers in C++ because the things you would use that sort of thing for are what virtual functions are for.
If you are determined to use this approach, I would suggest you not use C++ at all, and only use C.
To prove these pointer types are completely incompatible, here is a program for you:
#include <cstdio>
struct Foo {
int a;
int b;
int addThem() { return a + b; }
};
struct Bar {
int c;
int d;
int addThemAll() { return c + d; }
};
struct Qux : public Foo, public Bar {
int e;
int addAllTheThings() { return Foo::addThem() + Bar::addThemAll() + e; }
};
int addThemGlobal(Foo *foo)
{
return foo->a + foo->b;
}
int main()
{
int (Qux::*func)();
func = &Bar::addThemAll;
printf("sizeof(Foo::addThem) == %u\n", sizeof(&Foo::addThem));
printf("sizeof(Bar::addThemAll) == %u\n", sizeof(&Bar::addThemAll));
printf("sizeof(Qux::addAllTheThings) == %u\n", sizeof(&Qux::addAllTheThings));
printf("sizeof(func) == %u\n", sizeof(func));
printf("sizeof(addThemGlobal) == %u\n", sizeof(&addThemGlobal));
printf("sizeof(void *) == %u\n", sizeof(void *));
return 0;
}
On my system this program yields these results:
$ /tmp/a.out
sizeof(Foo::addThem) == 16
sizeof(Bar::addThemAll) == 16
sizeof(Qux::addAllTheThings) == 16
sizeof(func) == 16
sizeof(addThemGlobal) == 8
sizeof(void *) == 8
Notice how the member function pointer is 16 bytes long. It won't fit into a void *. It isn't a pointer in the normal sense. Your code and union work purely by accident.
The reason for this is that a member function pointer often needs extra data stored in it related to fixing up the object pointer it's passed in order to be correct for the function that's called. In my example, when called Bar::addThemAll on a Qux object (which is perfectly valid because of inheritance) the pointer to the Qux object needs to be adjusted to point at the Bar sub-object before the function is called. So Qux::*s to member functions must have this adjustment encoded in them. After all, saying func = &Qux::addAllTheThings is perfectly valid, and if that function were called no pointer adjustment would be necessary. So the pointer adjustment is a part of the function pointer's value.
And that's just an example. Compilers are permitted to implement member function pointers in any way they see fit (within certain constraints). Many compilers (like the GNU C++ compiler on a 64-bit platform like I was using) will implement them in a way that do not permit any member function pointer to be treated as at all equivalent to normal function pointers.
There are ways to deal with this. The swiss-army knife of dealing with member function pointers is the ::std::function template in C++11 or C++ TR1.
An example:
#include <functional>
// .... inside main
::std::function<int(Qux *)> funcob = func;
funcob can point at absolutely anything that can be called like a function and needs a Qux *. Member functions, global functions, static member functions, functors... funcob can point at it.
That example only works on a C++11 compiler though. But if your compiler is reasonably recent, but still not a C++11 compiler, this may work instead:
#include <tr1/functional>
// .... inside main
::std::tr1::function<int(Qux *)> funcob = func;
If worse comes to worse, you can use the Boost libraries, which is where this whole concept came from.
But I would rethink your design. I suspect that you will get a lot more milage out of having a well thought out inheritance hierarchy and using virtual functions than you will out of whatever it is you're doing now. With an interpreter I would have a top level abstract 'expression' class that is an abstract class for anything that can be evaluated. I would give it a virtual evaluate method. Then you can derive classes for different syntax elements like an addition expression a variable or a constant. Each of them will overload the evaluate method for their specific case. Then you can build up expression trees.
Not knowing details though, that's just a vague suggestion about your design.
Here is a clean solution. By means of a template wrap your member function into a static member function. Then you can convert it to whatever pointer you want:
template<class F, void (F::*funct)()>
struct Helper: public T {
static void static_f(F *obj) {
((*obj).*funct)();
};
};
struct T {
void f() {
}
};
int main() {
void (*ptr)(T*);
ptr = &(Helper<T,&T::f>::static_f);
}
It seems that you need to convert a pointer to a member function to a void *. I presume you want to give that pointer as a "user data" to some library function and then you will get back your pointer and want to use it on some given object.
If this is the case a reinterpret_cast<void *>(...) could be the right thing... I assume that the library receiving the pointer is not using it.
Hi I am trying to learn some function pointers in C/C++ and I was trying to write the following C++ code with gcc on Ubuntu.
This code should execute the multiply or or the add function depending on the
preprocessor flag -DADD or -DMULTIPLY provided during compilation
#include <iostream>
#include <iomanip>
//Adds two numbers
int add(int a, int b)
{
return a+b;
}
//Multiplies two numbers
int multiply(int a, int b)
{
return a*b;
}
//Function to set the correct function to be executed.
//All functions here should have the same signature.
void functionsetter( void (*ptr2fun)(int,int) )
{
#ifdef ADD
ptr2fun = add;
#endif
#ifdef MULTIPLY
ptr2fun = multiply
#endif
}
int main(int argc, char *argv[])
{
int a = 5;
int b = 6;
void (*foo)(int,int);
functionsetter(foo);
return 0;
}
I cannot figure out how to pass the function pointer foo to the function-setter function by reference. Can someone help me out on this.I am sure the declaration of
functionsetter is wrong in the code, Please let me know how to fix it.
I am trying to compile this with g++ -O2 -g -Wall -DADD main.cpp -o main
Note: I want to use such preprocessor flags and function pointers in some other-code elsewhere.
Please let me know if such a thing is a good idea / practice.
Without using a typedef, the syntax for a reference to a function pointer is:
void functionsetter(void (*&ptr2fun)(int, int)) { ... }
But it is generally simpler to create a typedef for the pointer type:
typedef void (*FunctionPointer)(int, int);
void functionsetter(FunctionPointer& ptr2fun) { ... }
Or for the function type:
typedef void Function(int, int);
void functionsetter(Function*& ptr2fun) { ... }
Use a typedef:
typedef void (*MyFunctionPointer)(int,int);
void functionsetter(MyFunctionPointer& fp);
I want to use such preprocessor flags and function pointers in some other-code elsewhere. Please let me know if such a thing is a good idea / practice.
No, not really. It isn't clear from your example what you are trying to accomplish, but your implementation is rather unusual. Consider using virtual member functions or std::function to switch function implementations at runtime, or (possibly) templates to switch them at compile-time. There's nothing wrong with using conditional compilation for static selection like this, but mixing that with function pointers is a bit odd.
Without a good understanding of the problem you are trying to solve, it's difficult to give good advice as to how best to solve it.
You'd change your signature to:
void functionsetter( void (*&ptr2fun)(int,int) )
Note that the ptr2fun function pointer has the wrong signature, your add and multiply functions return an int, and so should ptr2fun
This becomes a lot easier if you use a typedef:
typedef int (*ptr2fun)(int,int);
void functionsetter(ptr2fun& func) { ...
Though, personally I'd just return the function pointer.
ptr2fun functionsetter()
{
#ifdef ADD
return add;
#endif
#ifdef MULTIPLY
return multiply
#endif
}
First, you're not passing a function pointer reference to the method, you're just passing a function pointer. You need to change the method signature to
void functionsetter( void (*&ptr2fun)(int,int) )
Also, your method signature is void(*)(int,int) in some places and int(*)(int,int) in some, they should probably be the latter everywhere since your add and multiply methods return int.
That said, since you're using C++, manipulating pointers in this manner isn't something I'd recommend, C++ has inheritance/virtual methods that can usually replace most function pointer use and makes the code much more readable and extensible.
I think I may be suffering from the dreaded "accidental programmer" disease, at least when it comes to typedefs and function pointers. So I've been experimenting with all kinds of combinations involving these to analyse the results based on all the output I get.
But as I kept on trying different combinations, instead of analyzing the results I'm now just lost in process.
I'm hoping you guys will help me figure out this mess.
First code example
typedef void (print)(void);
void do_something (void) { printf("Hello World\n"); }
print *pr;
pr = &do_something;
pr(); // Hello World
Second code example
typedef void (print)(void);
void do_something (void) { printf("Hello World\n"); }
print *pr;
pr = do_something;
pr(); // Hello World
How do both the above code examples work, it's as if '&' has no effect on function name
third code example
typedef void (print)(void);
void do_something (void) { printf("Hello World\n"); }
print pr;
pr = do_something; // compile error
pr = &do_something; // compile error
pr();
I was hoping one of the above assignments to work here but damn! I really don't understand function pointers (and maybe typedef too).
The address of a function name and the plain function name both mean the same thing, so & has no effect on a function name.
Similarly, when using function pointers, multiple dereferencing isn't a problem:
#include <stdio.h>
typedef void print(void);
static void dosomething(void) { printf("Hello World\n"); }
int main(void)
{
print *f1 = dosomething;
print *f2 = &dosomething;
f2();
(f1)();
(*f1)();
(**f2)();
(***f1)();
(****f2)();
(*****f1)();
}
That compiles cleanly under:
gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -std=c99 xx.c -o xx
I would not claim that multiple stars is good style; it isn't. It is 'odd, and (yes, you may say it) perverse'. One is sufficient (and the one star is mainly for people like me who learned to program in C before the standard said "it is OK to call a function via a pointer without using the (*pointer_to_function)(arg1, arg2) notation; you can just write pointer_to_function(arg1, arg2) if you like"). Yes, it is weird. No, no other type (or class of types) exhibits the same behaviour, thank goodness.
The thing about function pointers is that they're function pointers! :-) This is how you get your third sample to work:
#include <stdio.h>
typedef void (*print)(void);
// ^
void do_something (void) { printf("Hello World\n"); }
int main (void) {
print pr;
pr = do_something; // &do_something would also work.
pr();
return 0;
}
In terms of whether you use funcName or &funcName, it doesn't matter (in C at least). Section 6.3.2.1 Lvalues, arrays and function designators states:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
It turns out that, in C/C++, both funcname and &funcname will yield the address of funcname and can be assigned to a function pointer variable. This is actually just an oddity of how the syntax was designed for the language(s).
Like C, C++ has pointer to functions: void (*)() for example is a pointer to a function that takes no argument and returns no value. However, C++ has also introduced references to functions void (&)() and there are implicit conversions between the two (though I don't remember the rules exactly).
Therefore:
funcname is a reference to function
&funcname is a pointer to function
Note that taking the address (or a reference to) a function that is overloaded requires a static_cast to the exact type (to resolve the overload).
How does the C++ compiler decide which function/method to call if there are multiple possibilities?
In my specific case I have the standard free function of the C++ Run time and I also have a templated free variant, like this:
// The definitions of the C++ Run Time Library (from memory.h)
extern malloc(size_t s);
extern void free(void *p);
// Our own memory management functions
extern void *OurMalloc(size_t s);
extern void OurFree(void *p);
// Own variants to overrule malloc and free (instead of using #define)
template<typename T>
void *malloc(T t)
{
return OurMalloc(t);
}
template<typename T>
void free(T *t)
{
OurFree(t);
}
I tested this using the following code:
void main(void)
{
void *p = malloc(10);
free(p);
}
If I compile and run this, it seems that the call to malloc is correctly replaced by the templated variant. So far, so good.
However, the call to free is not replaced by the templated variant, and the standard C++ function is still called.
What rules does the C++ compiler use to decide which variant to give priority?
Is this related to the Koenig-lookup rules?
Note: I tried this alternative because using #define does not solve the problem (see question How to use C macro's (#define) to alter calls but not prototypes).
Overload resolution is quite complicated in general.
In your case, it is quite easy: a function template is not considered if there is an exact match. For free it is the case (the standard free takes a void*), for malloc it isn't (the standard malloc takes a size_t, you are passing an int and size_t can't be a typedef for int -- size_t is unsigned). If you call free with a type other than void*, it should instantiate your template.
Running:
#include <iostream>
void* ml(size_t s)
{
std::cout << "ml(size_t)\n";
}
void fr(void *p)
{
std::cout << "fr(void*)\n";
}
template<typename T>
void* ml(T t)
{
std::cout << "ml<" << typeid(T).name() << ">(T)\n";
}
template<typename T>
void fr(T *t)
{
std::cout << "fr<" << typeid(T).name() << ">(T*)\n";
}
int main()
{
void* p1 = ml((size_t)10);
fr(p1);
int* p2 = (int*)ml(10);
fr(p2);
return 0;
}
I get
ml(size_t)
fr(void*)
ml<i>(T)
fr<i>(T*)
and i is what returns typeid(int).name()
For your particular issue about malloc and free, the problem is that in your call to malloc:
void *p = malloc(10);
the parameter 10 is typed as an int, while the signature for the runtime's malloc() calls for an unsigned argument. Since there's not an exact match, the compiler prefers the templated malloc where it can create an exact match.
When you call:
free(p);
the type of p is void* which does exactly match the runtime's signature for free() so the compiler doesn't bother using the templated free.
It is not possible to "replace" the standard malloc using this technique. Other answers have already explained that because you are using a signed value as an argument in malloc call, your templated version happens to "win" over the standard one because the standard one expects an unsigned argument.
To better illustrate this I just wanted to add that if you supply either an unsigned int or unsigned long argument in your malloc call
void *p1 = malloc(10u);
void *p2 = malloc(10ul);
and you'll notice that in one of these calls your templated version of malloc also doesn't "work" anymore and the standard one is called instead, since it is a better match for the argument (provided that on your platform size_t is defined as either unsigned int or unsigned long)
Not answering the question you asked, but what it seems like you're trying to do:
If it's available on your system, you can use LD_PRELOAD to preload a .so library you build that has your versions of malloc and free. Then they will definitely be called instead of the standard versions.