Reputation: 14281
I am writing a thread spawning function of the prototype:
void Thread_create(void (*func)(void*), int argc, ...);
I have passed the argument count in so there is no problem determining the length. The problem is how do I recast func to a function with argc length and then call it using the arguments that I have?
EDIT: I also have constrained the function to only accept void* arguments (i.e. no need to worry about any other type being passed in)
For example:
void foo(void *bar, void *baz);
void fooTwo(void *bar, void *baz, void *bam);
int main(int argc, char *argv[]){
Thread_create(&foo, 2, (void*)argv[0], (void*)argv[1]); //foo gets called in a new thread with the arguments: argv[0] and argv[1]
Thread_create(&fooTwo, 3, (void*)argv[0], (void*)argv[1], (void*)argv[2]); //fooTwo gets called in a new thread with the arguments: argv[0] and argv[1] and argv[2]
return 0;
}
Side note: a solution of the form
Thread_create(void (*func)(void*), int argc, ...); //call with 1 arg
Thread_create(void (*func)(void*, void*), int argc, ...); //call with 2 args
Thread_create(void (*func)(void*, void*, void*), int argc, ...); //call with 3 args
doesn't work because I cannot pass that information across the thread create library call, whether it may be pthread_create or the windows ThreadCreate function.
Upvotes: 0
Views: 1356
Reputation: 541
Well, you can't construct a stack frame yourself, programmatically, unless you know the CPU architecture and ABI of the platform in question and code it yourself.
For instance, with general calling conventions on x86 32 bit, you need to pass arguments to the stack in reverse order (e.g. last argument first), then invoke the function via call, and once it returns clean the stack by popping up the values (or by adjusting the stack pointer).
So for a function "foo(int bar, int baz)" you would:
pushl <value-for-baz>
pushl <value-for-bar>
call foo
addl 8, $esp
Perhaps you could also code this in C, but messing with the stack from C would definitely require some assembly magic.
Also, stack frames may even look different when using different compiler flags. x86_64 puts arguments in registers first, and only uses the stack when there are more arguments than registers.
In short, don't do that. :)
The only alternative would be to create a large conditional, where each branch would call the proper function with the required number of arguments, or overloaded function as you proposed, or using a data structure to pass this information, like outlined in the other answer.
Thread_create(void (*func)(void), int argc, ...)
{
if (argc == 1)
((void (*)(void *)) func)(arg0);
else if (argc == 2)
((void (*)(void *, void *)) func)(arg0, arg1);
}
Upvotes: 2
Reputation: 131907
What you're trying to do isn't what variable arguments are for. Better just take an aditional void*
parameter that gets passed back to the user function. This is the usual way that callbacks with user data are implemented.
typedef void (*ThreadMainFunc)(void*);
void ThreadCreate(ThreadMainFunc func, void* user_data){
// do whatever you need to do
func(user_data);
// whatever else
}
struct ThreadData{
// arguments here as member
int arg1;
double arg2;
};
void MyThreadMain(void* my_data){
ThreadData* my_real_data =(ThreadData*)my_data;
// use my_real_data here
}
int main(){
ThreadData data;
data.arg1 = 42;
data.arg2 = 13.37;
CreateThread(&MyThreadMain,&data);
// ^^^^^ --- you don't need to cast to void, only from void
}
Upvotes: 1