我正在编写原型的线程产生函数:
void Thread_create(void (*func)(void*), int argc, ...);
我已经通过了参数计数,因此确定长度没有问题。 问题是如何将func重新赋值为具有argc长度的函数,然后使用我拥有的参数调用它?
编辑:我也限制了函数只接受void *参数(即不需要担心传入任何其他类型)
例如:
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;
}
附注:表格
的解决方案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
不起作用,因为我无法通过线程创建库调用传递该信息,无论是pthread_create还是windows ThreadCreate函数。
答案 0 :(得分:2)
嗯,除非您了解相关平台的CPU架构和ABI并自行编码,否则您无法以编程方式自行构建堆栈帧。
例如,对于x86 32位的通用调用约定,您需要以相反的顺序将参数传递给堆栈(例如,最后一个参数优先),然后通过调用调用该函数,并且一旦它通过弹出返回清理堆栈值(或通过调整堆栈指针)。
所以对于一个函数" foo(int bar,int baz)"你会:
pushl <value-for-baz>
pushl <value-for-bar>
call foo
addl 8, $esp
也许你也可以用C编写代码,但是从C中搞乱堆栈肯定需要一些装配魔法。
此外,使用不同的编译器标志时,堆栈帧甚至可能看起来不同。 x86_64首先将参数放在寄存器中,并且只有当参数多于寄存器时才使用堆栈。
简而言之,不要这样做。 :)
唯一的选择是创建一个大的条件,其中每个分支将使用所需数量的参数调用正确的函数,或者按照您的建议调用重载函数,或使用数据结构传递此信息,如其他答案。
Thread_create(void (*func)(void), int argc, ...)
{
if (argc == 1)
((void (*)(void *)) func)(arg0);
else if (argc == 2)
((void (*)(void *, void *)) func)(arg0, arg1);
}
答案 1 :(得分:1)
您要做的不是变量参数的用途。最好只需要一个传递回用户函数的aditional void*
参数。这是实现用户数据回调的常用方法。
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
}