输入void void *(*)(void *)为void(*)(void)

作为赋值的一部分,我试图创建一个像pthreads这样的用户级线程库。

为了处理线程之间的上下文切换,我使用’swapcontext’函数。 在使用它之前,我必须使用’makecontext’函数创建一个上下文。 ‘makecontext’需要一个返回类型为void且参数类型为(void)的函数指针。

然而,线程函数必须是void* thread_func (void*)

有没有办法进行类型转换? 或者是否有其他方法在用户级别进行上下文切换?

通过将函数的地址转换为不同的原型并通过结果指针调用它来调用具有不兼容原型的函数是非法的:

 void *my_callback(void *arg) { ... } void (*broken)(void *) = (void (*)(void *)) my_callback; broken(some_arg); // incorrect, my_callback returns a `void *` 

你可以做的是传递给makecontext你自己的回调,它将调用thread_func并忽略它的返回值。 一个仅用于调用另一个函数的小函数有时称为蹦床

 /* return type is compatible with the prototype of the callback received by makecontext; simply calls the real callback */ static void trampoline(int cb, int arg) { void *(*real_cb)(void *) = (void *(*)(void *)) cb; void *real_arg = arg; real_cb(real_arg); } int my_pthread_create(void *(*cb)(void *), void *arg) { ucontext_t *ucp; ... /* For brevity treating `void *` as the same size as `int` - DO NOT USE AS-IS. makecontext exposes an annoyingly inconvenient API that only accepts int arguments; correct code would deconstruct each pointer into two ints (on architectures where pointer is larger than int) and reconstruct them in the trampoline. */ makecontext(ucp, trampoline, 2, (int) cb, (int) arg); ... } 

对于奖励积分,您可以修改trampoline以存储回调函数在堆栈上返回的void *值,并使用等效的pthread_join()检索它。

原则上,你总是可以将任何类型的指针强制转换为任何其他类型的指针,但对于函数指针,我强烈建议不要这样做

你的thread_func会期望堆栈上的一个参数,如果在你的错误播放后调用它将不会被提供。 更糟糕的是, thread_func会在不应该的地方写一个返回值,从而破坏你的堆栈。

解决方案是将调用包装在适当类型的自己的函数中。

您可以像变量一样对函数指针进行类型转换。 语法更尴尬,但它肯定是可能的(这是一个好主意是完全是另一个讨论)。

但在这种情况下,它可能不是你想要做的。 从swapcontext的手册页 :

在调用makecontext()之前,调用者必须为此上下文分配一个新堆栈,并将其地址分配给ucp-> uc_stack,

你的线程函数需要一个参数。 通过您创建的堆栈将该参数传递给新上下文。 传递给makecontext()函数可以是一个包装函数,它从堆栈中检索值并将其作为参数传递给线程函数。 单独的类型转换不会提供一种方法,用于将参数中的数据下移到新上下文中的函数。