环绕一个 C 函数,该函数在 C++ 中使用 void* 接受其参数

Wrapping around a C function that takes its arguments with void* in C++

我正在包装来自 freeRTOS 的 C 函数,它创建一个任务并在 C++ 中使用 void 指针获取其参数。该函数看起来有点像这样:

void createTask(TaskFunction_t taskCode, void * args);

据我所知,要将 2 个参数传递给任务,我需要创建一个结构,将其地址转换为 void*,传递它,然后将其转换回原始状态,如下所示:

struct Params
{
    const int a;
    const double b;
};

static void task(void * args)
{
   auto params = *static_cast<Params*>(args);
   // do something with params.a and params.b
}

int main()
{
   Params params{1, 2.2};
   createTask(task, static_cast<void*>(&params));
}

包装此函数的首选方式是什么,以便我可以传递可变类型的可变数量的参数?我应该只留下 void * args 作为参数,还是可以用模板或元组来做一些事情来稍微简化这个过程。

从 C++11 开始,你可以使用类似

的东西
static void call_task(void *args) {
    auto& f = *static_cast<std::function<void()>*>(args);
    f();
}
// note: need this to stay alive!
std::function<void()> f = [&](){
    // Any arguments you like here
    do_whatever(1, 2, 3)
};
CreateTask(call_task, static_cast<void*>(&f));

您需要确保 f 的生命周期长于任务的生命周期(就像您对 Params 对象所做的那样)。


您实际上可以完全避免 std::function,因为:

template<typename Func>
void call_func(void *args) {
    auto& f = *static_cast<Func*>(args);
    f();
}

template<typename Func>
void wrapped_create_task(Func& func) {
    CreateTask(call_func<Func>, static_cast<void*>(&func));
}
// you can still use `std::function` here, but you don't have to.
auto f = [&](){
    // Any arguments you like here
    do_whatever(1, 2, 3)
};

// this works on any object that implements `operator ()`
wrapped_create_task(f)

同样,非常重要 f 在执行期间保持活动状态。你不能把它放在一个在任务完成之前就死掉的堆栈上。