I have a void pointer (args) and I want that pointer to point to a function pointer. I have this:
1 2 3 4 5 6
Thread(void (*workerFunction)())
{
args = newvoid*; //Create space to store a function pointer
*args = workerFunction; //Store the function pointer
startThread(realWorkerFunction0);
}
But I get errors like "Illegal indirection" at line 4 (of this code block). As you can see this is a constructor. Line 5 is not really of concern here.
What am I doing wrong and how can I get the job done?
Well actually, I have 127 different constructors which create a struct to store on the heap, thats where args point to, but since this constructor creates a struct which only contains the function 'workerFunction', I wanted to skip the creation of the struct, to produce a bit less code. So I'm not 'bunging different types of values into a void*' to save tinsy-winsy space, but to save 127 object of incremental size.
What I'm actually are doing: I'm creating a class named Thread which support up to 127 arguments which you can pass to you worker function. But it wasn't really related to my question :P
The problem is that a void* can be smaller than a function pointer on some systems.
Its probably better to use a union like this:
1 2 3 4 5 6 7 8 9 10 11 12 13
union stuff
{
my_usual_struct* sp;
(void)(*fp)();
};
stuff args;
// store a struct
args.sp = new my_usual_struct;
// store a function pointer
args.fp = workerFunction
There is almost always a better way of doing things than resorting to these tactics.
That's the whole point about using a union. Its as big as its largest member and no bigger. It solves the problem of unequal sized pointers without taking up additional space.
void * is as big as the largest possible data pointer. Otherwise, it would be completely useless as a generic pointer.
The fact that function pointers can be larger than data pointers is but the tip of a massive iceberg.
Function pointers also hold (at compile time) the pointed function's calling convention as type information. This is to keep you from doing stupid things like
1 2 3 4 5
//Pretend I used the calling convention syntax right, although I probably didn't.
typedefvoid __cdecl (*fp)();
void __stdcall f();
fp p=(fp)f; //Correct return type, correct function signature, but wrong calling convention.
p(); //Enjoy your corrupted stack!
Now, this is not a problem if you're consistent with your calling conventions. The real problem is when a function in a dynamic library takes a callback pointer and the dumbass user forgets to read the damn documentation.
And let's not get into the whole problem of member function pointers.
There's simply no such thing as a "generic function pointer". Explicitly cast function pointers at your own peril.
PS: Note that in any system that implements Windows' GetProcAddress() or UNIX's dlsym() (both necessary for dynamic linking, which makes any system that doesn't implement them, virtually useless), it's safe to cast function pointers to void *. Whether it's safe to cast this to a given function pointer type and call that, is a different matter.
void * is as big as the largest possible data pointer. Otherwise, it would be completely useless as a generic pointer.
Yes, I knew that, but my concern was actually that I'm not sure if that's safe. Can you be sure that the converted void pointer contains valid data of that function pointer?
Oh. Disregard the first paragraph. I misread "void (*)()" as "void *", for some reason.
Like I said, void * is big enough to point to any regular function on Windows and UNIX systems. You can check that using predefined macros. The real problem is casting the pointer back to the correct type.
Why exactly do you want to do this, anyway? What's wrong with the traditional method of passing generic pointers to structures? It's easy to implement, hard to screw up, and it works everywhere.
What's wrong with the traditional method of passing generic pointers to structures? It's easy to implement, hard to screw up, and it works everywhere.
I think that what you mean is that I put the function pointer in a struct and point to that struct instead to the function pointer, that's what I did eventually.